def parse_parameters(state): """(11.2.1)""" state["major_version"] = read_uint(state) # (11.2.2) Check the major_version is at least 1. (It may need to be # higher depending on the features used on the sequence, but this will be # checked as the stream is processed. Later, at the end of the stream we'll # also check the major_version was not too high for the set of features # actually used.) ## Begin not in spec if state["major_version"] < MINIMUM_MAJOR_VERSION: raise MajorVersionTooLow(state["major_version"]) ## End not in spec state["minor_version"] = read_uint(state) # (11.2.2) Check the minor_version is 0. ## Begin not in spec if state["minor_version"] != 0: raise MinorVersionNotZero(state["minor_version"]) ## End not in spec state["profile"] = read_uint(state) # (C.2) Profile must be a supported value assert_in_enum(state["profile"], Profiles, BadProfile) ## Not in spec # (11.2.2) Profile must be supported by current version ## Begin not in spec minimum_required_version = profile_version_implication(state["profile"]) if state["major_version"] < minimum_required_version: raise ProfileNotSupportedByVersion(state["profile"], state["major_version"]) log_version_lower_bound(state, minimum_required_version) ## End not in spec state["level"] = read_uint(state) # (C.3) Level must be a supported value assert_in_enum(state["level"], Levels, BadLevel) ## Not in spec # (C.3) Levels may constrain the order and choice of data units in a # sequence. See the various level standards documents (e.g. ST 2042-2) for # details. ## Begin not in spec if "_level_sequence_matcher" not in state: state["_level_sequence_matcher"] = Matcher( LEVEL_SEQUENCE_RESTRICTIONS[state["level"]].sequence_restriction_regex ) # If we're at this point we're currently reading the first sequence # header (in the first data unit) of a sequence. Advance the state # machine accordingly. assert state["_level_sequence_matcher"].match_symbol("sequence_header") ## End not in spec # (C.3) Levels may constrain the allowed profiles and versions ## Begin not in spec assert_level_constraint(state, "level", state["level"]) assert_level_constraint(state, "profile", state["profile"]) assert_level_constraint(state, "major_version", state["major_version"]) assert_level_constraint(state, "minor_version", state["minor_version"])
def frame_size(state, video_parameters): """(11.4.3)""" custom_dimensions_flag = read_bool(state) # (C.3) Check level allows this value ## Begin not in spec assert_level_constraint(state, "custom_dimensions_flag", custom_dimensions_flag) ## End not in spec if custom_dimensions_flag: video_parameters["frame_width"] = read_uint(state) # (C.3) Check level allows this value ## Begin not in spec assert_level_constraint(state, "frame_width", video_parameters["frame_width"]) ## End not in spec video_parameters["frame_height"] = read_uint(state) # (C.3) Check level allows this value ## Begin not in spec assert_level_constraint(state, "frame_height", video_parameters["frame_height"]) ## End not in spec # Errata: spec doesn't prevent zero-pixel pictures # # (11.4.3) Frames must be at least one pixel wide and tall ## Begin not in spec if ( video_parameters["frame_width"] == 0 or video_parameters["frame_height"] == 0 ): raise ZeroPixelFrameSize( video_parameters["frame_width"], video_parameters["frame_height"], )
def transform_parameters(state): """(12.4.1)""" state["wavelet_index"] = read_uint(state) # (12.4.1) Check wavelet type is supported ## Begin not in spec assert_in_enum(state["wavelet_index"], WaveletFilters, BadWaveletIndex) ## End not in spec # (C.3) Check level allows this wavelet type ## Begin not in spec assert_level_constraint(state, "wavelet_index", state["wavelet_index"]) ## End not in spec state["dwt_depth"] = read_uint(state) # (C.3) Check level allows this wavelet depth assert_level_constraint(state, "dwt_depth", state["dwt_depth"]) ## Not in spec state["wavelet_index_ho"] = state["wavelet_index"] state["dwt_depth_ho"] = 0 if state["major_version"] >= 3: extended_transform_parameters(state) slice_parameters(state) quant_matrix(state)
def pixel_aspect_ratio(state, video_parameters): """(11.4.7)""" custom_pixel_aspect_ratio_flag = read_bool(state) # (C.3) Check level allows custom pixel aspect ratio ## Begin not in spec assert_level_constraint( state, "custom_pixel_aspect_ratio_flag", custom_pixel_aspect_ratio_flag ) ## End not in spec if custom_pixel_aspect_ratio_flag: index = read_uint(state) # (C.3) Check level allows the specified preset ## Begin not in spec assert_level_constraint(state, "pixel_aspect_ratio_index", index) ## End not in spec if index == 0: video_parameters["pixel_aspect_ratio_numer"] = read_uint(state) # (C.3) Check level allows the specified numerator ## Begin not in spec assert_level_constraint( state, "pixel_aspect_ratio_numer", video_parameters["pixel_aspect_ratio_numer"], ) ## End not in spec video_parameters["pixel_aspect_ratio_denom"] = read_uint(state) # (C.3) Check level allows the specified denominator ## Begin not in spec assert_level_constraint( state, "pixel_aspect_ratio_denom", video_parameters["pixel_aspect_ratio_denom"], ) ## End not in spec # Errata: spec fails to require ratio to be non-zero on either side # # (11.4.7) ratio must not contain zeros ## Begin not in spec if ( video_parameters["pixel_aspect_ratio_numer"] == 0 or video_parameters["pixel_aspect_ratio_denom"] == 0 ): raise PixelAspectRatioContainsZeros( video_parameters["pixel_aspect_ratio_numer"], video_parameters["pixel_aspect_ratio_denom"], ) ## End not in spec else: # (11.4.7) Pixel aspect ratio preset must be a known value ## Begin not in spec assert_in_enum(index, PresetPixelAspectRatios, BadPresetPixelAspectRatio) ## End not in spec preset_pixel_aspect_ratio(video_parameters, index)
def clean_area(state, video_parameters): """(11.4.8)""" custom_clean_area_flag = read_bool(state) # (C.3) Check level allows custom clean area ## Begin not in spec assert_level_constraint(state, "custom_clean_area_flag", custom_clean_area_flag) ## End not in spec if custom_clean_area_flag: video_parameters["clean_width"] = read_uint(state) # (C.3) Check level allows this width ## Begin not in spec assert_level_constraint(state, "clean_width", video_parameters["clean_width"]) ## End not in spec video_parameters["clean_height"] = read_uint(state) # (C.3) Check level allows this height ## Begin not in spec assert_level_constraint(state, "clean_height", video_parameters["clean_height"]) ## End not in spec video_parameters["left_offset"] = read_uint(state) # (C.3) Check level allows this offset ## Begin not in spec assert_level_constraint(state, "left_offset", video_parameters["left_offset"]) ## End not in spec video_parameters["top_offset"] = read_uint(state) # (C.3) Check level allows this offset ## Begin not in spec assert_level_constraint(state, "top_offset", video_parameters["top_offset"]) ## End not in spec # (11.4.8) The clean area is restricted to being within the existing # picture area ## Begin not in spec if not ( video_parameters["clean_width"] + video_parameters["left_offset"] <= video_parameters["frame_width"] and video_parameters["clean_height"] + video_parameters["top_offset"] <= video_parameters["frame_height"] ): raise CleanAreaOutOfRange( video_parameters["clean_width"], video_parameters["clean_height"], video_parameters["left_offset"], video_parameters["top_offset"], video_parameters["frame_width"], video_parameters["frame_height"], )
def transfer_function(state, video_parameters): """(11.4.10.4)""" custom_transfer_function_flag = read_bool(state) # (C.3) Check level allows custom transfer functions ## Begin not in spec assert_level_constraint( state, "custom_transfer_function_flag", custom_transfer_function_flag ) ## End not in spec if custom_transfer_function_flag: index = read_uint(state) # (11.4.10.3) Index should be a supported value ## Begin not in spec assert_in_enum(index, PresetTransferFunctions, BadPresetTransferFunction) ## End not in spec # (C.3) Check level allows the specified preset ## Begin not in spec assert_level_constraint(state, "transfer_function_index", index) ## End not in spec # (11.2.2) Preset must be supported by current version ## Begin not in spec minimum_required_version = preset_transfer_function_version_implication(index) if state["major_version"] < minimum_required_version: raise PresetTransferFunctionNotSupportedByVersion( index, state["major_version"] ) log_version_lower_bound(state, minimum_required_version) ## End not in spec preset_transfer_function(video_parameters, index)
def color_spec(state, video_parameters): """(11.4.10.1)""" custom_color_spec_flag = read_bool(state) # (C.3) Check level allows custom color specs ## Begin not in spec assert_level_constraint(state, "custom_color_spec_flag", custom_color_spec_flag) ## End not in spec if custom_color_spec_flag: index = read_uint(state) # (11.4.10.1) Index should be a supported value assert_in_enum(index, PresetColorSpecs, BadPresetColorSpec) ## Not in spec # (C.3) Check level allows the specified preset assert_level_constraint(state, "color_spec_index", index) ## Not in spec preset_color_spec(video_parameters, index) if index == 0: color_primaries(state, video_parameters) color_matrix(state, video_parameters) transfer_function(state, video_parameters) ## Begin not in spec else: # (11.2.2) Color spec must be supported by current version minimum_required_version = preset_color_spec_version_implication(index) if state["major_version"] < minimum_required_version: raise PresetColorSpecNotSupportedByVersion( index, state["major_version"] ) log_version_lower_bound(state, minimum_required_version)
def scan_format(state, video_parameters): """(11.4.5)""" custom_scan_format_flag = read_bool(state) # (C.3) Check level allows custom scan formats ## Begin not in spec assert_level_constraint(state, "custom_scan_format_flag", custom_scan_format_flag) ## End not in spec if custom_scan_format_flag: video_parameters["source_sampling"] = read_uint(state) # (11.4.5) Mode be a known value ## Begin not in spec assert_in_enum( video_parameters["source_sampling"], SourceSamplingModes, BadSourceSamplingMode, ) ## End not in spec # (C.3) Check level allows this value ## Begin not in spec assert_level_constraint( state, "source_sampling", video_parameters["source_sampling"], )
def color_diff_sampling_format(state, video_parameters): """(11.4.4)""" custom_color_diff_format_flag = read_bool(state) # (C.3) Check level allows custom color difference sampling ## Begin not in spec assert_level_constraint( state, "custom_color_diff_format_flag", custom_color_diff_format_flag ) ## End not in spec if custom_color_diff_format_flag: video_parameters["color_diff_format_index"] = read_uint(state) # (11.4.4) Index shall be a known value ## Begin not in spec assert_in_enum( video_parameters["color_diff_format_index"], ColorDifferenceSamplingFormats, BadColorDifferenceSamplingFormat, ) ## End not in spec # (C.3) Check level allows this value ## Begin not in spec assert_level_constraint( state, "color_diff_format_index", video_parameters["color_diff_format_index"], )
def extended_transform_parameters(state): """(12.4.4.1)""" asym_transform_index_flag = read_bool(state) # (C.3) Check level allows an asymmetric transform types ## Begin not in spec assert_level_constraint(state, "asym_transform_index_flag", asym_transform_index_flag) ## End not in spec if asym_transform_index_flag: state["wavelet_index_ho"] = read_uint(state) # (12.4.4.2) Check wavelet type is supported ## Begin not in spec assert_in_enum(state["wavelet_index_ho"], WaveletFilters, BadHOWaveletIndex) ## End not in spec # (C.3) Check level allows this wavelet type ## Begin not in spec assert_level_constraint(state, "wavelet_index_ho", state["wavelet_index_ho"]) ## End not in spec asym_transform_flag = read_bool(state) # (C.3) Check level allows an asymmetric transform depths ## Begin not in spec assert_level_constraint(state, "asym_transform_flag", asym_transform_flag) ## End not in spec if asym_transform_flag: state["dwt_depth_ho"] = read_uint(state) # (C.3) Check level allows this wavelet depth ## Begin not in spec assert_level_constraint(state, "dwt_depth_ho", state["dwt_depth_ho"]) ## End not in spec # (11.2.2) Log increased minimum version requirements if an asymmetric # transform was used. ## Begin not in spec minimum_required_version = wavelet_transform_version_implication( state["wavelet_index"], state["wavelet_index_ho"], state["dwt_depth_ho"], ) log_version_lower_bound(state, minimum_required_version)
def signal_range(state, video_parameters): """(11.4.9)""" custom_signal_range_flag = read_bool(state) # (C.3) Check level allows custom signal range ## Begin not in spec assert_level_constraint(state, "custom_signal_range_flag", custom_signal_range_flag) ## End not in spec if custom_signal_range_flag: index = read_uint(state) # (C.3) Check level allows the specified preset ## Begin not in spec assert_level_constraint(state, "custom_signal_range_index", index) ## End not in spec if index == 0: video_parameters["luma_offset"] = read_uint(state) # (C.3) Check level allows this offset ## Begin not in spec assert_level_constraint( state, "luma_offset", video_parameters["luma_offset"] ) ## End not in spec video_parameters["luma_excursion"] = read_uint(state) # (C.3) Check level allows this excursion ## Begin not in spec assert_level_constraint( state, "luma_excursion", video_parameters["luma_excursion"] ) ## End not in spec # (11.4.9) Check luma_excursion is valid # # Errata: Spec fails to constrain excursions. Excursions *must* be # >= 1 or the pseudocode behaviour will be undefined. ## Begin not in spec if video_parameters["luma_excursion"] < 1: raise BadCustomSignalExcursion( "luma", video_parameters["luma_excursion"] ) ## End not in spec video_parameters["color_diff_offset"] = read_uint(state) # (C.3) Check level allows this offset ## Begin not in spec assert_level_constraint( state, "color_diff_offset", video_parameters["color_diff_offset"] ) ## End not in spec video_parameters["color_diff_excursion"] = read_uint(state) # (C.3) Check level allows this excursion ## Begin not in spec assert_level_constraint( state, "color_diff_excursion", video_parameters["color_diff_excursion"] ) ## End not in spec # (11.4.9) Check color_diff_excursion is valid # # Errata: Spec fails to constrain excursions. Excursions *must* be # >= 1 or the pseudocode behaviour will be undefined. ## Begin not in spec if video_parameters["color_diff_excursion"] < 1: raise BadCustomSignalExcursion( "color_diff", video_parameters["color_diff_excursion"] ) ## End not in spec else: # (11.4.9) Signal range preset must be a known value ## Begin not in spec assert_in_enum(index, PresetSignalRanges, BadPresetSignalRange) ## End not in spec # (11.2.2) Signal range preset must be supported by current version ## Begin not in spec minimum_required_version = preset_signal_range_version_implication(index) if state["major_version"] < minimum_required_version: raise PresetSignalRangeNotSupportedByVersion( index, state["major_version"] ) log_version_lower_bound(state, minimum_required_version) ## End not in spec preset_signal_range(video_parameters, index)
def frame_rate(state, video_parameters): """(11.4.6)""" custom_frame_rate_flag = read_bool(state) # (C.3) Check level allows custom frame rates ## Begin not in spec assert_level_constraint(state, "custom_frame_rate_flag", custom_frame_rate_flag) ## End not in spec if custom_frame_rate_flag: index = read_uint(state) # (C.3) Check level allows the specified preset assert_level_constraint(state, "frame_rate_index", index) ## Not in spec if index == 0: video_parameters["frame_rate_numer"] = read_uint(state) # (C.3) Check level allows the specified numerator ## Begin not in spec assert_level_constraint( state, "frame_rate_numer", video_parameters["frame_rate_numer"], ) ## End not in spec video_parameters["frame_rate_denom"] = read_uint(state) # (C.3) Check level allows the specified denominator ## Begin not in spec assert_level_constraint( state, "frame_rate_denom", video_parameters["frame_rate_denom"], ) ## End not in spec # Errata: spec doesn't prevent divide-by-zero in custom frame rate # fractions. # # (11.4.6) frame_rate_denom must not be zero (i.e. a divide by zero) ## Begin not in spec if video_parameters["frame_rate_denom"] == 0: raise FrameRateHasZeroDenominator(video_parameters["frame_rate_numer"]) ## End not in spec # Errata: spec doesn't prevent 0 fps # # (11.4.6) frame_rate_numer must not be zero (i.e. 0 fps) ## Begin not in spec if video_parameters["frame_rate_numer"] == 0: raise FrameRateHasZeroNumerator(video_parameters["frame_rate_denom"]) ## End not in spec else: # (11.4.6) Frame rate preset must be a known value ## Begin not in spec assert_in_enum(index, PresetFrameRates, BadPresetFrameRateIndex) ## End not in spec # (11.2.2) Frame rate preset must be supported by current version ## Begin not in spec minimum_required_version = preset_frame_rate_version_implication(index) if state["major_version"] < minimum_required_version: raise PresetFrameRateNotSupportedByVersion( index, state["major_version"] ) log_version_lower_bound(state, minimum_required_version) ## End not in spec preset_frame_rate(video_parameters, index)
def sequence_header(state): """(11.1)""" # Record this sequence_header as it appears in the bitstream ## Begin not in spec this_sequence_header_offset = tell(state)[0] record_bitstream_start(state) ## End not in spec parse_parameters(state) base_video_format = read_uint(state) # (11.4.1) Check base video format is supported ## Begin not in spec assert_in_enum(base_video_format, BaseVideoFormats, BadBaseVideoFormat) ## End not in spec # (C.3) Check level allows this base format ## Begin not in spec assert_level_constraint(state, "base_video_format", base_video_format) ## End not in spec video_parameters = source_parameters(state, base_video_format) state["picture_coding_mode"] = read_uint(state) # (11.5) Ensure picture coding mode is valid ## Begin not in spec assert_in_enum( state["picture_coding_mode"], PictureCodingModes, BadPictureCodingMode ) ## End not in spec # (C.3) Check level allows this picture coding mode ## Begin not in spec assert_level_constraint(state, "picture_coding_mode", state["picture_coding_mode"]) ## End not in spec set_coding_parameters(state, video_parameters) # Errata: The spec only says the frame_height must be an integer multiple # of the color_diff_height but, in addition, the luma_height should be a # multiple and the color_diff_width should be a multiple of # luma_width/frame_width # # (11.6.2) Check frame_height is an integer multiple of color_diff_height ## Begin not in spec if ( # Prevent divide-by-zero in tests below state["luma_height"] == 0 or state["luma_width"] == 0 or state["color_diff_height"] == 0 or state["color_diff_width"] == 0 or # Actually check multiples video_parameters["frame_height"] % state["luma_height"] != 0 or video_parameters["frame_width"] % state["luma_width"] != 0 or video_parameters["frame_height"] % state["color_diff_height"] != 0 or video_parameters["frame_width"] % state["color_diff_width"] != 0 ): raise PictureDimensionsNotMultipleOfFrameDimensions( state["luma_width"], state["luma_height"], state["color_diff_width"], state["color_diff_height"], video_parameters["frame_width"], video_parameters["frame_height"], ) ## End not in spec # (11.1) Check that the this sequence_header is byte-for-byte identical # with the previous sequence_header in the sequence ## Begin not in spec this_sequence_header_bytes = record_bitstream_finish(state) if "_last_sequence_header_bytes" in state: if this_sequence_header_bytes != state["_last_sequence_header_bytes"]: raise SequenceHeaderChangedMidSequence( state["_last_sequence_header_offset"], state["_last_sequence_header_bytes"], this_sequence_header_offset, this_sequence_header_bytes, ) state["_last_sequence_header_bytes"] = this_sequence_header_bytes state["_last_sequence_header_offset"] = this_sequence_header_offset ## End not in spec return video_parameters
def quant_matrix(state): """(12.4.5.3)""" custom_quant_matrix = read_bool(state) # (C.3) Check level allows use of custom quantisation matrices ## Begin not in spec assert_level_constraint(state, "custom_quant_matrix", custom_quant_matrix) ## End not in spec if custom_quant_matrix: # (C.3) Check that quantisation matrix values are in the level-defined # range ## Begin not in spec allowed_values = allowed_values_for( LEVEL_CONSTRAINTS, "quant_matrix_values", state["_level_constrained_values"], ) def check(quant_matrix_value): assert_in( quant_matrix_value, allowed_values, QuantisationMatrixValueNotAllowedInLevel, state["_level_constrained_values"], ) ## End not in spec # NB: For historical reasons, we use a dict not an array in this # implementation. ### state["quant_matrix"] = new_array(state["dwt_depth_ho"] + state["dwt_depth"] + 1) state["quant_matrix"] = {} ## Not in spec if state["dwt_depth_ho"] == 0: state["quant_matrix"][0] = {} state["quant_matrix"][0]["LL"] = read_uint(state) check(state["quant_matrix"][0]["LL"]) ## Not in spec else: state["quant_matrix"][0] = {} state["quant_matrix"][0]["L"] = read_uint(state) check(state["quant_matrix"][0]["L"]) ## Not in spec for level in range(1, state["dwt_depth_ho"] + 1): state["quant_matrix"][level] = {} state["quant_matrix"][level]["H"] = read_uint(state) check(state["quant_matrix"][level]["H"]) ## Not in spec for level in range(state["dwt_depth_ho"] + 1, state["dwt_depth_ho"] + state["dwt_depth"] + 1): state["quant_matrix"][level] = {} state["quant_matrix"][level]["HL"] = read_uint(state) check(state["quant_matrix"][level]["HL"]) ## Not in spec state["quant_matrix"][level]["LH"] = read_uint(state) check(state["quant_matrix"][level]["LH"]) ## Not in spec state["quant_matrix"][level]["HH"] = read_uint(state) check(state["quant_matrix"][level]["HH"]) ## Not in spec else: # (12.4.5.3) If no custom quantisation matrix has been specified, a # default table must be available ## Begin not in spec configuration = ( state["wavelet_index"], state["wavelet_index_ho"], state["dwt_depth"], state["dwt_depth_ho"], ) if configuration not in QUANTISATION_MATRICES: raise NoQuantisationMatrixAvailable(*configuration) ## End not in spec set_quant_matrix(state)
def slice_parameters(state): """(12.4.5.2)""" state["slices_x"] = read_uint(state) # (C.3) Check level allows this number of horizontal slices assert_level_constraint(state, "slices_x", state["slices_x"]) ## Not in spec state["slices_y"] = read_uint(state) # (C.3) Check level allows this number of vertical slices assert_level_constraint(state, "slices_y", state["slices_y"]) ## Not in spec # Errata: Spec doesn't prevent zero-slice pictures # # (12.4.5.2) Must have at least once slice ## Begin not in spec if state["slices_x"] == 0 or state["slices_y"] == 0: raise ZeroSlicesInCodedPicture(state["slices_x"], state["slices_y"]) ## End not in spec # (C.3) Check if this level expects slice counts which result in every # slice having the same number of transform components ## Begin not in spec assert_level_constraint(state, "slices_have_same_dimensions", slices_have_same_dimensions(state)) ## End not in spec if is_ld(state): state["slice_bytes_numerator"] = read_uint(state) # (C.3) Check level allows the specified numerator ## Begin not in spec assert_level_constraint(state, "slice_bytes_numerator", state["slice_bytes_numerator"]) ## End not in spec state["slice_bytes_denominator"] = read_uint(state) # (C.3) Check level allows the specified denominator ## Begin not in spec assert_level_constraint(state, "slice_bytes_denominator", state["slice_bytes_denominator"]) ## End not in spec # Errata: spec doesn't disallow a slice_bytes_denominator of zero # # (12.4.5.2) Must have non-zero slice_bytes denominator (i.e. no divide # by zero) ## Begin not in spec if state["slice_bytes_denominator"] == 0: raise SliceBytesHasZeroDenominator(state["slice_bytes_numerator"]) ## End not in spec # Errata: spec doesn't disallow slice_bytes_* values which evaluate to # less than one byte. # # (12.4.5.2) slice_bytes_numerator/slice_bytes_denominator must be # greater than or equal to one byte to avoid zero-byte slices in the # bitstream. ## Begin not in spec if state["slice_bytes_numerator"] < state["slice_bytes_denominator"]: raise SliceBytesIsLessThanOne( state["slice_bytes_numerator"], state["slice_bytes_denominator"], ) ## End not in spec if is_hq(state): state["slice_prefix_bytes"] = read_uint(state) # (C.3) Check level allows the specified prefix byte count ## Begin not in spec assert_level_constraint(state, "slice_prefix_bytes", state["slice_prefix_bytes"]) ## End not in spec state["slice_size_scaler"] = read_uint(state) # Errata: not enforced in spec # # (12.4.5.2) slice size scaler should not be zero ## Begin not in spec if state["slice_size_scaler"] == 0: raise SliceSizeScalerIsZero() ## End not in spec # (C.3) Check level allows the specified slice size scaler ## Begin not in spec assert_level_constraint(state, "slice_size_scaler", state["slice_size_scaler"])