def test_function_in_main_codebase(self): try: # Should crash due to invalid base video format index video_parameters.set_source_defaults(-1) except: # noqa: 722 exc_type, exc_value, exc_tb = sys.exc_info() assert most_recent_pseudocode_function(exc_tb) == "set_source_defaults (11.4.2)"
def test_complete(self): assert ( count_video_parameter_differences( VideoParameters(set_source_defaults(BaseVideoFormats.hd1080p_50)), VideoParameters(set_source_defaults(BaseVideoFormats.hd1080p_60)), ) == 2 ) # frame_rate_{numer,denom}
def test_mismatched_top_field_first(self): base_video_parameters = set_source_defaults(BaseVideoFormats.custom_format) video_parameters = set_source_defaults(BaseVideoFormats.hd1080p_50) level_constraints_dict = defaultdict(AnyValue) assert ( list( iter_source_parameter_options( base_video_parameters, video_parameters, level_constraints_dict ) ) == [] )
def source_parameters(serdes, state, base_video_format): """ (11.4.1) Parse the video source parameters. Returns a VideoParameters object. """ video_parameters = set_source_defaults(base_video_format) with serdes.subcontext("frame_size"): frame_size(serdes, state, video_parameters) with serdes.subcontext("color_diff_sampling_format"): color_diff_sampling_format(serdes, state, video_parameters) with serdes.subcontext("scan_format"): scan_format(serdes, state, video_parameters) with serdes.subcontext("frame_rate"): frame_rate(serdes, state, video_parameters) with serdes.subcontext("pixel_aspect_ratio"): pixel_aspect_ratio(serdes, state, video_parameters) with serdes.subcontext("clean_area"): clean_area(serdes, state, video_parameters) with serdes.subcontext("signal_range"): signal_range(serdes, state, video_parameters) with serdes.subcontext("color_spec"): color_spec(serdes, state, video_parameters) return video_parameters
def test_unsatisfiable_level_constraints(self): base_video_parameters = set_source_defaults(BaseVideoFormats.hd720p_50) video_parameters = set_source_defaults(BaseVideoFormats.hd1080p_50) level_constraints_dict = defaultdict( AnyValue, custom_dimensions_flag=ValueSet(False), ) assert ( list( iter_source_parameter_options( base_video_parameters, video_parameters, level_constraints_dict ) ) == [] )
def rank_base_video_format_similarity( video_parameters, base_video_formats=list(BaseVideoFormats), ): """ Given a set of :py:class:`~vc2_conformance.pseudocode.video_parameters.VideoParameters`, return an ordered list of :py:class:`~vc2_data_tables.BaseVideoFormats` with the most similar format first and least similar last. .. note:: The returned :py:class:`~vc2_data_tables.BaseVideoFormats` will always have the same ``top_field_first`` setting. Parameters ========== video_parameters : :py:class:`~vc2_conformance.pseudocode.video_parameters.VideoParameters` The video parameters against which to rank base video formats' similarity. base_video_formats : [:py:class:`~vc2_data_tables.BaseVideoFormats`, ...] Optional. The base video format indices to consider. Defaults to all base video formats. """ return sorted( (index for index in base_video_formats if (BASE_VIDEO_FORMAT_PARAMETERS[index].top_field_first == video_parameters["top_field_first"])), key=lambda index: count_video_parameter_differences( set_source_defaults(index), video_parameters, ), )
def test_valid_bitstream(self): # This test runs all of the option sets produced through the bitstream # generator to verify that 1: the dictionaries all contain the expected # fields and 2: that they encode the options they're supposed to. This # test also indirectly tests all of the contributing option generating # functions. base_video_format = BaseVideoFormats.hd1080p_50 video_parameters = set_source_defaults(base_video_format) level_constraints_dict = defaultdict(AnyValue) source_parameters_sets = list( iter_source_parameter_options( video_parameters, video_parameters, level_constraints_dict ) ) for context in source_parameters_sets: state = State() f = BytesIO() with Serialiser(BitstreamWriter(f), context) as ser: resulting_video_parameters = source_parameters( ser, state, base_video_format, ) assert resulting_video_parameters == video_parameters
def iter_sequence_headers(codec_features): """ Generate a series of :py:class:`~vc2_conformance.bitstream.SequenceHeader` objects which encode the video format specified in :py:class:`~vc2_conformance.codec_features.CodecFeatures` dictionary provided. This generator will start with an efficient encoding of the required features, built on the most closely matched base video format. This will be followed by successively less efficient encodings (i.e. using more custom fields) but the same (best-matched) base video format. After this, encodings based on other base video formats will be produced (again starting with the most efficient encoding for each format first). This generator may output no items if the VC-2 level specified does not permit the format given. Parameters ========== codec_features : :py:class:`~vc2_conformance.codec_features.CodecFeatures` Yields ====== sequence_header : :py:class:`~vc2_conformance.bitstream.SequenceHeader` """ picture_coding_mode = codec_features["picture_coding_mode"] video_parameters = codec_features["video_parameters"] constrained_values = codec_features_to_trivial_level_constraints( codec_features) # Level constraints may force us to use a particular base video format for # this encoding so we try all possible encodings (starting with the most # compact) and stop when we find one compliant with the level restrictions. base_video_formats = rank_allowed_base_video_format_similarity( codec_features) for base_video_format in base_video_formats: base_video_parameters = set_source_defaults(base_video_format) filtered_constraint_table = filter_constraint_table( LEVEL_CONSTRAINTS, dict(constrained_values, base_video_format=base_video_format), ) for level_constraints_dict in filtered_constraint_table: for source_parameters in iter_source_parameter_options( base_video_parameters, video_parameters, level_constraints_dict): yield SequenceHeader( parse_parameters=make_parse_parameters(codec_features), base_video_format=base_video_format, video_parameters=source_parameters, picture_coding_mode=picture_coding_mode, )
def source_parameters(state, base_video_format): """(11.4.1)""" video_parameters = set_source_defaults(base_video_format) frame_size(state, video_parameters) color_diff_sampling_format(state, video_parameters) scan_format(state, video_parameters) frame_rate(state, video_parameters) pixel_aspect_ratio(state, video_parameters) clean_area(state, video_parameters) signal_range(state, video_parameters) color_spec(state, video_parameters) return video_parameters
def codec_features(self): return CodecFeatures( name="example", level=Levels.unconstrained, profile=Profiles.high_quality, picture_coding_mode=PictureCodingModes.pictures_are_frames, video_parameters=set_source_defaults(BaseVideoFormats.hd1080p_50), wavelet_index=WaveletFilters.haar_with_shift, wavelet_index_ho=WaveletFilters.haar_with_shift, dwt_depth=2, dwt_depth_ho=0, slices_x=120, slices_y=108, fragment_slice_count=0, lossless=False, picture_bytes=1036800, quantization_matrix=None, )
def test_matching(self): video_parameters = set_source_defaults(BaseVideoFormats.hd1080p_50) ranking = rank_base_video_format_similarity(video_parameters) # Exact match assert ranking[0] == BaseVideoFormats.hd1080p_50 # Close match (source sampling differs) assert ranking[1] == BaseVideoFormats.hd1080i_50 # Next closest (frame rate numer/denom differs) assert set(ranking[2:5]) == set( [ BaseVideoFormats.hd1080i_60, BaseVideoFormats.hd1080p_60, BaseVideoFormats.hd1080p_24, ] )
def video_parameters(): video_parameters = set_source_defaults( tables.BaseVideoFormats.custom_format) # Low-resolution 4:2:0 format (matching the picture fixture above) video_parameters["frame_width"] = 4 video_parameters["frame_height"] = 4 video_parameters[ "color_diff_format_index"] = tables.ColorDifferenceSamplingFormats.color_4_2_0 video_parameters["clean_width"] = 4 video_parameters["clean_height"] = 4 # 100-bit luma samples: Not a whole number of bytes and not nearest to a # power-of-two bytes, and not a format Numpy natively supports video_parameters["luma_excursion"] = (1 << 100) - 1 # 8-bit color-diff samples: An exact number of bytes video_parameters["color_diff_excursion"] = 255 return video_parameters
def test_compute_dimensions_and_depths(): # Just to set all unimportant fields to something sensible vp = set_source_defaults(BaseVideoFormats.cif) vp["frame_width"] = 1000 vp["frame_height"] = 600 # Make luma and chroma different sizes vp["color_diff_format_index"] = ColorDifferenceSamplingFormats.color_4_2_0 # Make luma and chroma different depths vp["luma_excursion"] = 200 # 8 bits vp["color_diff_excursion"] = (1 << 18) - 100 # 18 bits # Make frame size differ from picture size pcm = PictureCodingModes.pictures_are_fields dd = compute_dimensions_and_depths(vp, pcm) assert list(dd.items()) == [ ( "Y", DimensionsAndDepths(width=1000, height=300, depth_bits=8, bytes_per_sample=1), ), ( "C1", DimensionsAndDepths(width=500, height=150, depth_bits=18, bytes_per_sample=4), ), ( "C2", DimensionsAndDepths(width=500, height=150, depth_bits=18, bytes_per_sample=4), ), ]
def test_covers_all_flag_states(self): # Checks that the examples produced show every flag in every possible # state (when the options we choose correspond with a base video # format). base_video_format = BaseVideoFormats.hd1080p_50 video_parameters = set_source_defaults(base_video_format) level_constraints_dict = defaultdict(AnyValue) source_parameters_sets = list( iter_source_parameter_options( video_parameters, video_parameters, level_constraints_dict ) ) # {flag_name: set([bool, ...]), ...} observed_flag_settings = defaultdict(set) for src_parameters in source_parameters_sets: flag_settings = {} def find_flags(d): if isinstance(d, dict): for key, value in d.items(): if key.endswith("_flag"): assert key not in flag_settings flag_settings[key] = value else: find_flags(value) find_flags(src_parameters) for flag, setting in flag_settings.items(): observed_flag_settings[flag].add(setting) assert all( settings == set([True, False]) for settings in observed_flag_settings.values() )
def test_top_field_first_always_matches(self, top_field_first): video_parameters = VideoParameters(top_field_first=top_field_first) for index in rank_base_video_format_similarity(video_parameters): assert set_source_defaults(index)["top_field_first"] == top_field_first
def test_basic_valid(self): assert read_codec_features_csv( [ "name, hd", "level, unconstrained, 0", "profile, high_quality, 3", "base_video_format, hd1080p_50, custom_format", "picture_coding_mode, pictures_are_frames, pictures_are_frames", "frame_width, default, 8", "frame_height, default, 4", "color_diff_format_index, default, color_4_4_4", "source_sampling, default, progressive", "top_field_first, default, TRUE", "frame_rate_numer, default, 1", "frame_rate_denom, default, 1", "pixel_aspect_ratio_numer, default, 1", "pixel_aspect_ratio_denom, default, 1", "clean_width, default, 8", "clean_height, default, 4", "left_offset, default, 0", "top_offset, default, 0", "luma_offset, default, 0", "luma_excursion, default, 255", "color_diff_offset, default, 128", "color_diff_excursion, default, 255", "color_primaries_index, default, hdtv", "color_matrix_index, default, hdtv", "transfer_function_index, default, tv_gamma", "wavelet_index, haar_with_shift, haar_with_shift", "wavelet_index_ho, haar_with_shift, haar_no_shift", "dwt_depth, 2, 2", "dwt_depth_ho, 0, 1", "slices_x, 120, 2", "slices_y, 108, 1", "fragment_slice_count, 0, 1", "lossless, FALSE, FALSE", "picture_bytes, 1036800, 24", "quantization_matrix, default, 0 0 0 0 0 0 0 0", ] ) == OrderedDict( [ ( "hd", CodecFeatures( name="hd", level=Levels.unconstrained, profile=Profiles.high_quality, picture_coding_mode=PictureCodingModes.pictures_are_frames, video_parameters=set_source_defaults( BaseVideoFormats.hd1080p_50 ), wavelet_index=WaveletFilters.haar_with_shift, wavelet_index_ho=WaveletFilters.haar_with_shift, dwt_depth=2, dwt_depth_ho=0, slices_x=120, slices_y=108, fragment_slice_count=0, lossless=False, picture_bytes=1036800, quantization_matrix=None, ), ), ( "column_C", CodecFeatures( name="column_C", level=Levels.unconstrained, profile=Profiles.high_quality, picture_coding_mode=PictureCodingModes.pictures_are_frames, video_parameters=VideoParameters( frame_width=8, frame_height=4, color_diff_format_index=ColorDifferenceSamplingFormats.color_4_4_4, # noqa: E501 source_sampling=SourceSamplingModes.progressive, top_field_first=True, frame_rate_numer=1, frame_rate_denom=1, pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, clean_width=8, clean_height=4, left_offset=0, top_offset=0, luma_offset=0, luma_excursion=255, color_diff_offset=128, color_diff_excursion=255, color_primaries_index=PresetColorPrimaries.hdtv, color_matrix_index=PresetColorMatrices.hdtv, transfer_function_index=PresetTransferFunctions.tv_gamma, ), wavelet_index=WaveletFilters.haar_with_shift, wavelet_index_ho=WaveletFilters.haar_no_shift, dwt_depth=2, dwt_depth_ho=1, slices_x=2, slices_y=1, fragment_slice_count=1, lossless=False, picture_bytes=24, quantization_matrix={ 0: {"L": 0}, 1: {"H": 0}, 2: {"HL": 0, "LH": 0, "HH": 0}, 3: {"HL": 0, "LH": 0, "HH": 0}, }, ), ), ] )
def read_codec_features_csv(csvfile): """ Read a set of :py:class:`CodecFeatures` from a CSV file in the format described by :ref:`codec-features`. .. If you're reading this, you probably can't click on the reference above... It points to the 'Defining codec features' section of ``docs/user_guide/generating_test_cases.rst`` Parameters ========== csvfile : iterable An iterable of lines from a CSV file, e.g. an open :py:class:`file` object. Returns ======= codec_feature_sets : OrderedDict([(name, :py:class:`CodecFeatures`), ...]) Raises ====== :py:exc:`InvalidCodecFeaturesError` Raised if the provided CSV contains invalid or incomplete data. .. note:: Validation largely extends only to syntactic issues (e.g. invalid integer values, 'picture_bytes' being specified for lossless formats etc). It does not include validation of 'deeper' issues such as too-small picture_bytes values or parameters not being permitted by the specified level. """ csv_columns = read_dict_list_csv(csvfile) out = OrderedDict() for i, column in zip(islice(spreadsheet_column_names(), 1, None), csv_columns): if not column: continue def pop(field_name, parser, *default_): """ Check for the existance of a value in the current column and return the native-type version of it. If a third argument, 'default', is given, the default value will be returned if the field contains the string "default". """ assert len(default_) in (0, 1) try: value = column.pop(field_name) if default_ and value.lower() == "default": return default_[0] else: return parser(value) except KeyError: raise InvalidCodecFeaturesError( "Missing entry for '{}' in '{}' column".format( field_name, name, ) ) except ValueError as e: raise InvalidCodecFeaturesError( "Invalid entry for '{}' in '{}' column: {} ({})".format( field_name, name, value, e, ) ) features = CodecFeatures() # Create default names for columns where not provided if "name" not in column: name = "column_{}".format(i) else: name = column.pop("name") name = name.strip() features["name"] = name # Check for name uniqueness if name in out: raise InvalidCodecFeaturesError( "Name '{}' used more than once".format(name) ) out[name] = features # Parse basic fields for field_name, field_type in [ ("level", partial(parse_int_enum, Levels)), ("profile", partial(parse_int_enum, Profiles)), ("picture_coding_mode", partial(parse_int_enum, PictureCodingModes)), ("wavelet_index", partial(parse_int_enum, WaveletFilters)), ("wavelet_index_ho", partial(parse_int_enum, WaveletFilters)), ("dwt_depth", partial(parse_int_at_least, 0)), ("dwt_depth_ho", partial(parse_int_at_least, 0)), ("slices_x", partial(parse_int_at_least, 1)), ("slices_y", partial(parse_int_at_least, 1)), ("fragment_slice_count", partial(parse_int_at_least, 0)), ("lossless", parse_bool), ]: features[field_name] = pop(field_name, field_type) features["video_parameters"] = set_source_defaults( pop( "base_video_format", partial(parse_int_enum, BaseVideoFormats), ) ) # Parse integer video_parameters fields for field_name, field_type in [ ("frame_width", partial(parse_int_at_least, 1)), ("frame_height", partial(parse_int_at_least, 1)), ( "color_diff_format_index", partial(parse_int_enum, ColorDifferenceSamplingFormats), ), ("source_sampling", partial(parse_int_enum, SourceSamplingModes)), ("top_field_first", parse_bool), ("frame_rate_numer", partial(parse_int_at_least, 1)), ("frame_rate_denom", partial(parse_int_at_least, 1)), ("pixel_aspect_ratio_numer", partial(parse_int_at_least, 1)), ("pixel_aspect_ratio_denom", partial(parse_int_at_least, 1)), ("clean_width", partial(parse_int_at_least, 0)), ("clean_height", partial(parse_int_at_least, 0)), ("left_offset", partial(parse_int_at_least, 0)), ("top_offset", partial(parse_int_at_least, 0)), ("luma_offset", partial(parse_int_at_least, 0)), ("luma_excursion", partial(parse_int_at_least, 1)), ("color_diff_offset", partial(parse_int_at_least, 0)), ("color_diff_excursion", partial(parse_int_at_least, 1)), ("color_primaries_index", partial(parse_int_enum, PresetColorPrimaries)), ("color_matrix_index", partial(parse_int_enum, PresetColorMatrices)), ( "transfer_function_index", partial(parse_int_enum, PresetTransferFunctions), ), ]: features["video_parameters"][field_name] = pop( field_name, field_type, features["video_parameters"][field_name], ) # Parse picture_bytes option if features["lossless"]: if "picture_bytes" in column: raise InvalidCodecFeaturesError( "Entry provided for 'picture_bytes' when lossless mode " "specified for '{}' column".format( name, ) ) features["picture_bytes"] = None else: features["picture_bytes"] = pop( "picture_bytes", partial(parse_int_at_least, 1), ) # Parse quantisation matrix features["quantization_matrix"] = pop( "quantization_matrix", partial( parse_quantization_matrix, features["dwt_depth"], features["dwt_depth_ho"], ), None, ) # Check for extraneous rows if column: raise InvalidCodecFeaturesError( "Unrecognised row(s): {}".format( ", ".join(set(column)), ) ) return out
def test_all_base_video_formats_sensible(self, base_video_format): # Sanity check that all base video formats are considered to make sense video_parameters = set_source_defaults(base_video_format) assert sanity_check_video_parameters(video_parameters)