def test_consistent_for_same_feed(self): vp = VideoParameters( frame_width=10, frame_height=5, color_diff_format_index=ColorDifferenceSamplingFormats.color_4_4_4, luma_offset=0, luma_excursion=1023, color_diff_offset=0, color_diff_excursion=511, ) p1 = list(white_noise(vp, PictureCodingModes.pictures_are_frames)) p2 = list(white_noise(vp, PictureCodingModes.pictures_are_frames)) p3 = list( white_noise(vp, PictureCodingModes.pictures_are_frames, seed=1337)) p4 = list( white_noise(vp, PictureCodingModes.pictures_are_frames, seed=1337)) assert p1 == p2 assert p1 != p3 assert p3 == p4
def test_progressive_to_split_fields(): pictures = [ np.arange(4 * 6 * 3).reshape(4, 6, 3) * 1, np.arange(4 * 6 * 3).reshape(4, 6, 3) * 10, np.arange(4 * 6 * 3).reshape(4, 6, 3) * 100, np.arange(4 * 6 * 3).reshape(4, 6, 3) * 1000, ] vp = VideoParameters(top_field_first=True) pcm = PictureCodingModes.pictures_are_fields expected = [ pictures[0][0::2, :, :], pictures[0][1::2, :, :], pictures[1][0::2, :, :], pictures[1][1::2, :, :], pictures[2][0::2, :, :], pictures[2][1::2, :, :], pictures[3][0::2, :, :], pictures[3][1::2, :, :], ] actual = iter(progressive_to_split_fields(vp, pcm, pictures)) for e in expected: assert np.array_equal(next(actual), e) assert list(actual) == [] vp["top_field_first"] = False expected = [ pictures[0][1::2, :, :], pictures[0][0::2, :, :], pictures[1][1::2, :, :], pictures[1][0::2, :, :], pictures[2][1::2, :, :], pictures[2][0::2, :, :], pictures[3][1::2, :, :], pictures[3][0::2, :, :], ] actual = iter(progressive_to_split_fields(vp, pcm, pictures)) for e in expected: assert np.array_equal(next(actual), e) assert list(actual) == []
def test_num_frames(self): vp = VideoParameters( frame_width=10, frame_height=5, color_diff_format_index=ColorDifferenceSamplingFormats.color_4_4_4, luma_offset=0, luma_excursion=1023, color_diff_offset=0, color_diff_excursion=511, ) p1 = list( white_noise(vp, PictureCodingModes.pictures_are_frames, num_frames=3)) p2 = list( white_noise(vp, PictureCodingModes.pictures_are_fields, num_frames=3)) assert len(p1) == 3 assert len(p2) == 6
def test_to_xyz_and_from_xyz_roundtrip( luma_offset, luma_excursion, color_diff_offset, color_diff_excursion, primaries, matrix, transfer_function, ): video_parameters = VideoParameters( color_diff_format_index=ColorDifferenceSamplingFormats.color_4_4_4, luma_offset=luma_offset, luma_excursion=luma_excursion, color_diff_offset=color_diff_offset, color_diff_excursion=color_diff_excursion, color_primaries_index=primaries, color_matrix_index=matrix, transfer_function_index=transfer_function, ) luma_bits = intlog2(luma_excursion + 1) color_diff_bits = intlog2(color_diff_excursion + 1) w, h = 6, 4 rand = np.random.RandomState(0) y = rand.randint(0, 2 ** luma_bits, (h, w)) c1 = rand.randint(0, 2 ** color_diff_bits, (h, w)) c2 = rand.randint(0, 2 ** color_diff_bits, (h, w)) xyz = to_xyz(y, c1, c2, video_parameters) assert xyz.shape == (h, w, 3) new_y, new_c1, new_c2 = from_xyz(xyz, video_parameters) assert np.array_equal(y, new_y) assert np.array_equal(c1, new_c1) assert np.array_equal(c2, new_c2)
def test_explain_ffmpeg_and_imagemagick_commands( explain, matrix, expect_supported, ): video_parameters = VideoParameters( frame_width=8, frame_height=8, color_diff_format_index=ColorDifferenceSamplingFormats.color_4_4_4, 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=1, clean_height=1, top_offset=0, left_offset=0, luma_offset=0, luma_excursion=255, color_diff_offset=128, color_diff_excursion=255, color_primaries_index=PresetColorPrimaries.hdtv, color_matrix_index=matrix, transfer_function_index=PresetTransferFunctions.tv_gamma, ) picture_coding_mode = PictureCodingModes.pictures_are_frames explanation = explain("foo.raw", video_parameters, picture_coding_mode) if expect_supported: assert "$ " in explanation assert not explanation.startswith("No") else: assert "$ " not in explanation assert explanation.startswith("No")
def video_parameters(self): return VideoParameters( frame_width=4, frame_height=4, color_diff_format_index=ColorDifferenceSamplingFormats.color_4_4_4, 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=4, clean_height=4, left_offset=0, top_offset=0, luma_offset=0, luma_excursion=1023, color_diff_offset=512, color_diff_excursion=1023, color_primaries_index=PresetColorPrimaries.hdtv, color_matrix_index=PresetColorMatrices.hdtv, transfer_function_index=PresetTransferFunctions.tv_gamma, )
def test_mid_gray(primaries, transfer_function): vp = VideoParameters( frame_width=10, frame_height=5, frame_rate_numer=1, frame_rate_denom=1, pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, source_sampling=SourceSamplingModes.progressive, top_field_first=True, color_diff_format_index=ColorDifferenceSamplingFormats.color_4_4_4, # The choice of primaries and transfer function should have no effect: # the color should be chosen at the code level, not the color model # level color_primaries_index=primaries, color_matrix_index=PresetColorMatrices.hdtv, transfer_function_index=transfer_function, # Set two wonky off-center ranges; the offsets should be ignored with the # 'mid gray' being the middle of the code range luma_offset=20, luma_excursion=150, color_diff_offset=100, color_diff_excursion=900, ) pictures = list(mid_gray(vp, PictureCodingModes.pictures_are_frames)) assert len(pictures) == 1 picture = pictures[0] y = np.array(picture["Y"]) c1 = np.array(picture["C1"]) c2 = np.array(picture["C2"]) assert np.array_equal(y, np.full(y.shape, 128)) assert np.array_equal(c1, np.full(c1.shape, 512)) assert np.array_equal(c2, np.full(c2.shape, 512))
def test_pipe(): vp = VideoParameters( source_sampling=SourceSamplingModes.interlaced, top_field_first=True, ) pcm = PictureCodingModes.pictures_are_frames def repeat_pictures(video_parameters, picture_coding_mode, iterable): assert video_parameters == vp assert picture_coding_mode == pcm for picture in iterable: yield picture yield picture @pipe(repeat_pictures) def picture_generator(video_parameters, picture_coding_mode, values): assert video_parameters == vp assert picture_coding_mode == pcm for value in values: yield value * 10 assert list(picture_generator(vp, pcm, [1, 2, 3])) == [10, 10, 20, 20, 30, 30]
HD_1440X1080I60_OVER_SD_SDI_CODEC_FEATURES = CodecFeatures( level=Levels.hd_over_sd_sdi, profile=Profiles.low_delay, picture_coding_mode=PictureCodingModes.pictures_are_fields, video_parameters=VideoParameters( frame_width=1440, frame_height=1080, color_diff_format_index=ColorDifferenceSamplingFormats.color_4_2_2, source_sampling=SourceSamplingModes.interlaced, top_field_first=True, frame_rate_numer=30000, frame_rate_denom=1001, pixel_aspect_ratio_numer=4, pixel_aspect_ratio_denom=3, clean_width=1440, clean_height=1080, left_offset=0, top_offset=0, luma_offset=64, luma_excursion=876, color_diff_offset=512, color_diff_excursion=896, color_primaries_index=PresetColorPrimaries.hdtv, color_matrix_index=PresetColorMatrices.hdtv, transfer_function_index=PresetTransferFunctions.tv_gamma, ), wavelet_index=WaveletFilters.le_gall_5_3, wavelet_index_ho=WaveletFilters.le_gall_5_3, dwt_depth=3, dwt_depth_ho=0, slices_x=90,
PictureCodingModes.pictures_are_frames, ) == expected) @pytest.mark.parametrize( "video_parameters,expected", [ # Sizes match, components all the same and match the bit width used in the # file format. ( VideoParameters( frame_width=200, frame_height=100, color_matrix_index=PresetColorMatrices.rgb, color_diff_format_index=ColorDifferenceSamplingFormats. color_4_4_4, luma_offset=0, luma_excursion=255, color_diff_offset=0, color_diff_excursion=255, ), ("Each component consists of 200x50 8 bit values. " "Expressible values run from 0 (video level 0.00) " "to 255 (video level 1.00)."), ), # Components differ in size ( VideoParameters( frame_width=200, frame_height=100, color_matrix_index=PresetColorMatrices.rgb,
def test_to_xyz(): # A crude samity check which verifies that the conversion steps appear to # work correctly # An esoteric video format which is easy to hand-evaluate and also test # subsampling video_parameters = VideoParameters( color_diff_format_index=ColorDifferenceSamplingFormats.color_4_2_2, luma_offset=0, luma_excursion=255, color_diff_offset=0, color_diff_excursion=255, color_primaries_index=PresetColorPrimaries.hdtv, color_matrix_index=PresetColorMatrices.rgb, transfer_function_index=PresetTransferFunctions.tv_gamma, ) # Find XYZ coordinates for White, black, red green and blue test_colors_rgb = np.array( [ [1.0, 0.0, 1.0, 0.0, 0.0], [1.0, 0.0, 0.0, 1.0, 0.0], [1.0, 0.0, 0.0, 0.0, 1.0], ] ) test_colors_xyz = np.matmul( LINEAR_RGB_TO_XYZ[video_parameters["color_primaries_index"]], test_colors_rgb, ) # The following test image is defined in the XYZ domain # # +---+---+---+---+---+---+---+---+---+---+ # |Wht|Wht|Blk|Blk|Red|Red|Grn|Grn|Blu|Blu| # +---+---+---+---+---+---+---+---+---+---+ # |Wht|Blk|Blk|Blk|Red|Blk|Grn|Blk|Blu|Blk| # +---+---+---+---+---+---+---+---+---+---+ # |Wht|Wht|Wht|Wht|Wht|Wht|Wht|Wht|Wht|Wht| # +---+---+---+---+---+---+---+---+---+---+ # |Blk|Blk|Blk|Blk|Blk|Blk|Blk|Blk|Blk|Blk| # +---+---+---+---+---+---+---+---+---+---+ # # This has the following features: # # * Row 0: Fully saturated colors in pairs of pixels # * Row 1: Colors paired with black (which after 4:2:2 subsampling will # result in darker colors (at least with the low-pass filter used here) # * Row 2: All white # * Row 3: All black test_colors_xyz_row = test_colors_xyz.T.reshape(-1, 3) row_0 = np.repeat(test_colors_xyz_row, 2, axis=0) row_1 = row_0.copy() row_1[1::2, :] = 0 row_2 = np.empty_like(row_0) row_2[:, 0] = row_0[0, 0] row_2[:, 1] = row_0[0, 1] row_2[:, 2] = row_0[0, 2] row_3 = np.empty_like(row_0) row_3[:, 0] = row_0[2, 0] row_3[:, 1] = row_0[2, 1] row_3[:, 2] = row_0[2, 2] test_picture_xyz = np.stack([row_0, row_1, row_2, row_3], axis=0) # Colors should come out as expected RGB values in GBR order g, b, r = from_xyz( test_picture_xyz, video_parameters, ) # First row: solid colors # Wht Blk Red Grn Blu assert np.allclose(r[0], [255, 0, 255, 0, 0], atol=1) assert np.allclose(g[0], [255, 255, 0, 0, 0, 0, 255, 255, 0, 0], atol=1) assert np.allclose(b[0], [255, 0, 0, 0, 255], atol=1) # Second row, dimmed R and B channels # Wht Blk Red Grn Blu assert np.allclose(r[1], [128, 0, 128, 0, 0], atol=1) assert np.allclose(g[1], [255, 0, 0, 0, 0, 0, 255, 0, 0, 0], atol=1) assert np.allclose(b[1], [128, 0, 0, 0, 128], atol=1) # Third row: all-white assert np.allclose(r[2], [255, 255, 255, 255, 255], atol=1) assert np.allclose(g[2], [255, 255, 255, 255, 255, 255, 255, 255, 255, 255], atol=1) assert np.allclose(b[2], [255, 255, 255, 255, 255], atol=1) # Fourth row: all-black assert np.allclose(r[3], [0, 0, 0, 0, 0], atol=1) assert np.allclose(g[3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], atol=1) assert np.allclose(b[3], [0, 0, 0, 0, 0], atol=1)
CodecFeatures( MINIMAL_CODEC_FEATURES, picture_coding_mode=PictureCodingModes.pictures_are_fields, ), # Test with very high, asymmetric bit depths. # # Here 'high' means 16 bits and 14 bits (for luma and color # difference). In practice no real codec is likely to use more than # 16 bits since any video format requiring greater dynamic range is # likely to need to turn to floating point anyway. CodecFeatures( MINIMAL_CODEC_FEATURES, video_parameters=VideoParameters( MINIMAL_CODEC_FEATURES["video_parameters"], luma_offset=0, luma_excursion=(1 << 16) - 1, color_diff_offset=(1 << 14) // 2, color_diff_excursion=(1 << 14) - 1, ), ), ] ] def test_names_unique(): for codec_features, test_cases in ALL_TEST_CASES: names = [tc.name for tc in test_cases] assert len(set(names)) == len(names) @pytest.mark.parametrize(
class TestCustomQuantizationMatrix(object): @pytest.mark.parametrize( "codec_features", [ # Lossless mode with not enough bits for test pattern CodecFeatures( MINIMAL_CODEC_FEATURES_WITH_CUSTOM_QUANT_MATRIX, video_parameters=VideoParameters( MINIMAL_CODEC_FEATURES_WITH_CUSTOM_QUANT_MATRIX[ "video_parameters"], luma_excursion=4, color_diff_excursion=4, ), lossless=True, picture_bytes=None, ), # Level prohibits using custom quantisation matrices CodecFeatures( MINIMAL_CODEC_FEATURES_WITH_CUSTOM_QUANT_MATRIX, level=Levels.uhd_over_hd_sdi, ), ], ) def test_skipped_cases(self, codec_features): assert len(list(custom_quantization_matrix(codec_features))) == 0 @pytest.mark.parametrize("lossless", [False, True]) @pytest.mark.parametrize( "asymmetric,constrain_level_zero,initial_quant_matrix,exp_matrices", [ # By default should produce all three examples ( False, False, { 0: { "LL": 0 }, 1: { "HL": 1, "LH": 1, "HH": 1 }, 2: { "HL": 1, "LH": 1, "HH": 1 }, }, { "zeros": [0, 0, 0, 0, 0, 0, 0], "arbitrary": [0, 1, 2, 3, 4, 5, 6], "default": [4, 2, 2, 0, 4, 4, 2], }, ), # If provided matrix matches a test case, that case should be omitted ( False, False, { 0: { "LL": 0 }, 1: { "HL": 0, "LH": 0, "HH": 0 }, 2: { "HL": 0, "LH": 0, "HH": 0 }, }, { "arbitrary": [0, 1, 2, 3, 4, 5, 6], "default": [4, 2, 2, 0, 4, 4, 2] }, ), # When no default matrix is available, should omit the default case ( True, False, { 0: { "LL": 0 }, 1: { "HL": 1, "LH": 1, "HH": 1 }, 2: { "HL": 1, "LH": 1, "HH": 1 }, }, { "zeros": [0, 0, 0, 0, 0, 0, 0], "arbitrary": [0, 1, 2, 3, 4, 5, 6] }, ), # When a level restricts the custom quant index values, this limit should be # obeyed ( False, True, { 0: { "LL": 0 }, 1: { "HL": 1, "LH": 1, "HH": 1 }, 2: { "HL": 1, "LH": 1, "HH": 1 }, }, { "arbitrary": [3, 4, 8, 3, 4, 8, 3] }, ), ], ) def test_generates_custom_quant_matrices( self, lossless, asymmetric, constrain_level_zero, initial_quant_matrix, exp_matrices, ): codec_features = CodecFeatures( MINIMAL_CODEC_FEATURES_WITH_CUSTOM_QUANT_MATRIX, wavelet_index_ho=(WaveletFilters.le_gall_5_3 if not asymmetric else WaveletFilters.fidelity), quantization_matrix=initial_quant_matrix, lossless=lossless, picture_bytes=(None if lossless else MINIMAL_CODEC_FEATURES_WITH_CUSTOM_QUANT_MATRIX[ "picture_bytes"]), ) with temporary_level_override(): if constrain_level_zero: # Sanity check assert LEVEL_CONSTRAINTS[0]["level"] == ValueSet(0) LEVEL_CONSTRAINTS[0]["quant_matrix_values"] = ValueSet(3, 4, 8) test_cases = list(custom_quantization_matrix(codec_features)) matrices = {} for test_case in test_cases: stream = test_case.value to_visit = list(stream["sequences"][0]["data_units"]) while to_visit: d = to_visit.pop(0) if isinstance(d, dict): for key, value in d.items(): if key == "quant_matrix": assert value["custom_quant_matrix"] matrix = value["quant_matrix"] if test_case.subcase_name in matrices: # All pictures should have same custom # quantization matrix assert matrix == matrices[ test_case.subcase_name] else: matrices[test_case.subcase_name] = matrix else: to_visit.append(value) assert matrices == exp_matrices
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_progressive_to_pictures(): pictures = [ np.arange(4 * 6 * 3).reshape(4, 6, 3) * 1, np.arange(4 * 6 * 3).reshape(4, 6, 3) * 10, np.arange(4 * 6 * 3).reshape(4, 6, 3) * 100, np.arange(4 * 6 * 3).reshape(4, 6, 3) * 1000, ] # Progressive, pictures are frames vp = VideoParameters( source_sampling=SourceSamplingModes.progressive, top_field_first=True, ) pcm = PictureCodingModes.pictures_are_frames expected = pictures actual = iter(progressive_to_pictures(vp, pcm, pictures)) for e in expected: assert np.array_equal(next(actual), e) assert list(actual) == [] # Progressive, pictures are fields vp = VideoParameters( source_sampling=SourceSamplingModes.progressive, top_field_first=True, ) pcm = PictureCodingModes.pictures_are_fields expected = [ pictures[0][0::2, :, :], pictures[0][1::2, :, :], pictures[1][0::2, :, :], pictures[1][1::2, :, :], pictures[2][0::2, :, :], pictures[2][1::2, :, :], pictures[3][0::2, :, :], pictures[3][1::2, :, :], ] actual = iter(progressive_to_pictures(vp, pcm, pictures)) for e in expected: assert np.array_equal(next(actual), e) assert list(actual) == [] # Interlaced, pictures are frames vp = VideoParameters( source_sampling=SourceSamplingModes.interlaced, top_field_first=True, ) pcm = PictureCodingModes.pictures_are_frames expected = [ np.stack(list(zip(pictures[0][0::2, :, :], pictures[1][1::2, :, :])), axis=0).reshape(4, 6, 3), np.stack(list(zip(pictures[2][0::2, :, :], pictures[3][1::2, :, :])), axis=0).reshape(4, 6, 3), ] actual = iter(progressive_to_pictures(vp, pcm, pictures)) for e in expected: assert np.array_equal(next(actual), e) assert list(actual) == [] # Interlaced, pictures are fields vp = VideoParameters( source_sampling=SourceSamplingModes.interlaced, top_field_first=True, ) pcm = PictureCodingModes.pictures_are_fields expected = [ pictures[0][0::2, :, :], pictures[1][1::2, :, :], pictures[2][0::2, :, :], pictures[3][1::2, :, :], ] actual = iter(progressive_to_pictures(vp, pcm, pictures)) for e in expected: assert np.array_equal(next(actual), e) assert list(actual) == []
def test_is_rgb_color(): for matrix_index in PresetColorMatrices: expected = matrix_index == PresetColorMatrices.rgb vp = VideoParameters(color_matrix_index=matrix_index) assert is_rgb_color(vp) is expected
def generate_picture( filename, pixel_values=0, picture_number=0, bit_width=10, luma_bit_width=None, color_diff_bit_width=None, picture_coding_mode=PictureCodingModes.pictures_are_fields, width=8, height=4, ): """ Generate a 4:2:0 color subsampled raw picture with the specified file name. Parameters ========== filename : str Filename to write the raw picture to. pixel_values : int or (2D-array, 2D-array, 2D-array) If an integer, a ``width`` x ``height`` picture with all pixel values set to that value will be generated. If a set of three 2D arrays, uses these for the picture. The second and third arrays must be exactly half the width and height of the first. picture_number: int The VC-2 picture number. bit_width : int Bit depth for pixel values. luma_bit_width : int Bit depth for luma pixel values (overrides bit_width). color_diff_bit_width : int Bit depth for color difference pixel values (overrides bit_width). picture_coding_mode : :py:class:`~vc2_data_tables.PictureCodingModes` The picture coding mode to use. width, height : int The dimensions of the picture to generate (not the frame dimensions). Ignored if pixel_values is given. """ if isinstance(pixel_values, int): pixel_values = ( np.full((height, width), pixel_values, dtype=np.int64), np.full((height // 2, width // 2), pixel_values, dtype=np.int64), np.full((height // 2, width // 2), pixel_values, dtype=np.int64), ) else: pixel_values = ( np.array(pixel_values[0]), np.array(pixel_values[1]), np.array(pixel_values[2]), ) height, width = pixel_values[0].shape assert pixel_values[1].shape == (height // 2, width // 2) assert pixel_values[2].shape == (height // 2, width // 2) if luma_bit_width is None: luma_bit_width = bit_width if color_diff_bit_width is None: color_diff_bit_width = bit_width if picture_coding_mode == PictureCodingModes.pictures_are_fields: height *= 2 video_parameters = VideoParameters( frame_width=width, frame_height=height, color_diff_format_index=ColorDifferenceSamplingFormats.color_4_2_0, 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=width, clean_height=height, left_offset=0, top_offset=0, luma_offset=0, luma_excursion=(1 << luma_bit_width) - 1, color_diff_offset=1 << (color_diff_bit_width - 1), color_diff_excursion=(1 << color_diff_bit_width) - 1, color_primaries_index=PresetColorPrimaries.hdtv, color_matrix_index=PresetColorMatrices.hdtv, transfer_function_index=PresetTransferFunctions.tv_gamma, ) picture = { "Y": pixel_values[0], "C1": pixel_values[1], "C2": pixel_values[2], "pic_num": picture_number, } write(picture, video_parameters, picture_coding_mode, filename)
def test_linear_ramps(primaries, transfer_function): vp = VideoParameters( frame_width=32, frame_height=16, frame_rate_numer=1, frame_rate_denom=1, pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, source_sampling=SourceSamplingModes.progressive, top_field_first=True, color_diff_format_index=ColorDifferenceSamplingFormats.color_4_4_4, color_primaries_index=primaries, color_matrix_index=PresetColorMatrices.rgb, transfer_function_index=transfer_function, luma_offset=0, luma_excursion=255, color_diff_offset=0, color_diff_excursion=255, ) pictures = list(linear_ramps(vp, PictureCodingModes.pictures_are_frames)) assert len(pictures) == 1 g = np.array(pictures[0]["Y"]) b = np.array(pictures[0]["C1"]) r = np.array(pictures[0]["C2"]) rgb = np.stack([r, g, b], axis=-1) / 255.0 # NB: The d_cinema_transfer_function does not map 1.0 to 1.0 so in that # special case we must add some slack here. if transfer_function == PresetTransferFunctions.d_cinema: atol = 0.05 else: atol = 0.0 assert np.all(np.isclose(rgb[0, 0, :], [0, 0, 0], atol=atol)) assert np.all(np.isclose(rgb[0, 31, :], [1, 1, 1], atol=atol)) assert np.all(np.isclose(rgb[4, 0, :], [0, 0, 0], atol=atol)) assert np.all(np.isclose(rgb[4, 31, :], [1, 0, 0], atol=atol)) assert np.all(np.isclose(rgb[8, 0, :], [0, 0, 0], atol=atol)) assert np.all(np.isclose(rgb[8, 31, :], [0, 1, 0], atol=atol)) assert np.all(np.isclose(rgb[12, 0, :], [0, 0, 0], atol=atol)) assert np.all(np.isclose(rgb[12, 31, :], [0, 0, 1], atol=atol)) # Whites should be pure whites for c1 in range(3): for c2 in range(3): assert np.all(np.isclose(rgb[0, :, c1], rgb[0, :, c2], atol=0.05)) # Colors should be pure primaries assert np.all(rgb[4:8, :, [1, 2]] == 0) assert np.all(rgb[8:12, :, [0, 2]] == 0) assert np.all(rgb[12:16, :, [0, 1]] == 0) # Bands should contain same values throughout assert np.all(rgb[0::4, :, :] == rgb[1::4, :, :]) assert np.all(rgb[0::4, :, :] == rgb[2::4, :, :]) assert np.all(rgb[0::4, :, :] == rgb[3::4, :, :]) if transfer_function == PresetTransferFunctions.linear: # Should be perfectly linear assert np.all( np.isclose(rgb[0, :, 0], np.linspace(0, 1, 32), atol=0.05)) assert np.all( np.isclose(rgb[4, :, 0], np.linspace(0, 1, 32), atol=0.05)) assert np.all( np.isclose(rgb[8, :, 1], np.linspace(0, 1, 32), atol=0.05)) assert np.all( np.isclose(rgb[12, :, 2], np.linspace(0, 1, 32), atol=0.05)) else: # Should be monotonic for other transfer functions, at least assert np.all((rgb[0, 1:, 0] - rgb[0, :-1, 0]) >= 0) assert np.all((rgb[4, 1:, 0] - rgb[0, :-1, 0]) >= 0) assert np.all((rgb[8, 1:, 1] - rgb[0, :-1, 0]) >= 0) assert np.all((rgb[12, 1:, 2] - rgb[0, :-1, 0]) >= 0)
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}, }, ), ), ] )
class TestIterCustomOptionsDicts(object): @pytest.mark.parametrize( "bvp,vp,lcd,exp", [ # Override required ( VideoParameters( frame_width=640, frame_height=480, ), VideoParameters( frame_width=1920, frame_height=1080, ), defaultdict(AnyValue), [ FrameSize( custom_dimensions_flag=True, frame_width=1920, frame_height=1080, ), ], ), # Override optional ( VideoParameters( frame_width=1920, frame_height=1080, ), VideoParameters( frame_width=1920, frame_height=1080, ), defaultdict(AnyValue), [ FrameSize( custom_dimensions_flag=False, ), FrameSize( custom_dimensions_flag=True, frame_width=1920, frame_height=1080, ), ], ), # Force no-custom by disallowing the custom flag ( VideoParameters( frame_width=1920, frame_height=1080, ), VideoParameters( frame_width=1920, frame_height=1080, ), defaultdict(AnyValue, custom_dimensions_flag=ValueSet(False)), [ FrameSize( custom_dimensions_flag=False, ) ], ), # Force no-custom by disallowing the required dimensions ( VideoParameters( frame_width=1920, frame_height=1080, ), VideoParameters( frame_width=1920, frame_height=1080, ), defaultdict(AnyValue, frame_height=ValueSet(720)), [ FrameSize( custom_dimensions_flag=False, ) ], ), # Force custom flag ( VideoParameters( frame_width=1920, frame_height=1080, ), VideoParameters( frame_width=1920, frame_height=1080, ), defaultdict(AnyValue, custom_dimensions_flag=ValueSet(True)), [ FrameSize( custom_dimensions_flag=True, frame_width=1920, frame_height=1080, ), ], ), # Make impossible ( VideoParameters( frame_width=1920, frame_height=720, ), VideoParameters( frame_width=1920, frame_height=1080, ), defaultdict(AnyValue, frame_height=ValueSet(720)), [], ), ], ) def test_no_presets(self, bvp, vp, lcd, exp): dicts = list( iter_custom_options_dicts( bvp, vp, lcd, dict_type=FrameSize, flag_key="custom_dimensions_flag", parameters=["frame_width", "frame_height"], ) ) assert dicts == exp @pytest.mark.parametrize( "bvp,vp,lcd,exp", [ # Custom required (no preset available) ( VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), VideoParameters( pixel_aspect_ratio_numer=2, pixel_aspect_ratio_denom=1, ), defaultdict(AnyValue), [ PixelAspectRatio( custom_pixel_aspect_ratio_flag=True, index=0, pixel_aspect_ratio_numer=2, pixel_aspect_ratio_denom=1, ), ], ), # Custom required (preset available) ( VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), VideoParameters( pixel_aspect_ratio_numer=4, pixel_aspect_ratio_denom=3, ), defaultdict(AnyValue), [ PixelAspectRatio( custom_pixel_aspect_ratio_flag=True, index=PresetPixelAspectRatios.reduced_horizontal_resolution, ), PixelAspectRatio( custom_pixel_aspect_ratio_flag=True, index=0, pixel_aspect_ratio_numer=4, pixel_aspect_ratio_denom=3, ), ], ), # Custom optional ( VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), defaultdict(AnyValue), [ PixelAspectRatio( custom_pixel_aspect_ratio_flag=False, ), PixelAspectRatio( custom_pixel_aspect_ratio_flag=True, index=PresetPixelAspectRatios.ratio_1_1, ), PixelAspectRatio( custom_pixel_aspect_ratio_flag=True, index=0, pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), ], ), # Force no-custom by disallowing the flag ( VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), defaultdict(AnyValue, custom_pixel_aspect_ratio_flag=ValueSet(False)), [ PixelAspectRatio( custom_pixel_aspect_ratio_flag=False, ) ], ), # Force no-custom by disallowing required indices ( VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), defaultdict(AnyValue, pixel_aspect_ratio_index=ValueSet(99)), [ PixelAspectRatio( custom_pixel_aspect_ratio_flag=False, ) ], ), # Force no full custom by disallowing 0 index ( VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), defaultdict( AnyValue, pixel_aspect_ratio_index=ValueSet( PresetPixelAspectRatios.ratio_1_1 ), ), [ PixelAspectRatio( custom_pixel_aspect_ratio_flag=False, ), PixelAspectRatio( custom_pixel_aspect_ratio_flag=True, index=PresetPixelAspectRatios.ratio_1_1, ), ], ), # Force full custom ( VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), defaultdict( AnyValue, custom_pixel_aspect_ratio_flag=ValueSet(True), pixel_aspect_ratio_index=ValueSet(0), ), [ PixelAspectRatio( custom_pixel_aspect_ratio_flag=True, index=0, pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), ], ), # Make impossible ( VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), VideoParameters( pixel_aspect_ratio_numer=1, pixel_aspect_ratio_denom=1, ), defaultdict( AnyValue, custom_pixel_aspect_ratio_flag=ValueSet(True), pixel_aspect_ratio_index=ValueSet(0), pixel_aspect_ratio_numer=ValueSet(1), pixel_aspect_ratio_denom=ValueSet(2), ), [], ), ], ) def test_with_presets(self, bvp, vp, lcd, exp): dicts = list( iter_custom_options_dicts( bvp, vp, lcd, dict_type=PixelAspectRatio, flag_key="custom_pixel_aspect_ratio_flag", parameters=["pixel_aspect_ratio_numer", "pixel_aspect_ratio_denom"], presets=PRESET_PIXEL_ASPECT_RATIOS, preset_index_constraint_key="pixel_aspect_ratio_index", ) ) assert dicts == exp @pytest.mark.parametrize( "bvp,vp,exp", [ # Values match ( VideoParameters( color_primaries_index=PresetColorPrimaries.hdtv, ), VideoParameters( color_primaries_index=PresetColorPrimaries.hdtv, ), [ ColorPrimaries( custom_color_primaries_flag=False, ), ColorPrimaries( custom_color_primaries_flag=True, index=PresetColorPrimaries.hdtv, ), ], ), # Values don't match ( VideoParameters( color_primaries_index=PresetColorPrimaries.uhdtv, ), VideoParameters( color_primaries_index=PresetColorPrimaries.hdtv, ), [ ColorPrimaries( custom_color_primaries_flag=True, index=PresetColorPrimaries.hdtv, ), ], ), ], ) def test_with_differing_key_names(self, bvp, vp, exp): dicts = list( iter_custom_options_dicts( bvp, vp, defaultdict(AnyValue), dict_type=ColorPrimaries, flag_key="custom_color_primaries_flag", parameters=[("color_primaries_index", "index")], preset_index_constraint_key="color_primaries_index", ) ) assert dicts == exp