def test_index_must_be_valid(self): state = bytes_to_state( serialise_to_bytes( bitstream.SignalRange( custom_signal_range_flag=True, index=tables.PresetSignalRanges.video_8bit, ), {}, {}, )) state["major_version"] = 3 decoder.signal_range(state, {}) state = bytes_to_state( serialise_to_bytes( bitstream.SignalRange( custom_signal_range_flag=True, index=9999, ), {}, {}, )) state["major_version"] = 3 with pytest.raises(decoder.BadPresetSignalRange) as exc_info: decoder.signal_range(state, {}) assert exc_info.value.index == 9999
def test_index_must_be_valid(self): state = bytes_to_state( serialise_to_bytes( bitstream.FrameRate( custom_frame_rate_flag=True, index=tables.PresetFrameRates.fps_25, ), {}, {}, )) state["major_version"] = 3 decoder.frame_rate(state, {}) state = bytes_to_state( serialise_to_bytes( bitstream.FrameRate( custom_frame_rate_flag=True, index=9999, ), {}, {}, )) state["major_version"] = 3 with pytest.raises(decoder.BadPresetFrameRateIndex) as exc_info: decoder.frame_rate(state, {}) assert exc_info.value.index == 9999
def test_disallows_unsupported_combinations(self): state = { "wavelet_index": tables.WaveletFilters.haar_no_shift, "wavelet_index_ho": tables.WaveletFilters.haar_no_shift, "dwt_depth": 1, "dwt_depth_ho": 1, } state.update( bytes_to_state( serialise_to_bytes( bitstream.QuantMatrix(custom_quant_matrix=False, ), state.copy(), ))) decoder.quant_matrix(state) state = { "wavelet_index": tables.WaveletFilters.haar_no_shift, "wavelet_index_ho": tables.WaveletFilters.haar_with_shift, "dwt_depth": 999, "dwt_depth_ho": 9999, } state.update( bytes_to_state( serialise_to_bytes( bitstream.QuantMatrix(custom_quant_matrix=False, ), state.copy(), ))) with pytest.raises(decoder.NoQuantisationMatrixAvailable) as exc_info: decoder.quant_matrix(state) assert exc_info.value.wavelet_index == tables.WaveletFilters.haar_no_shift assert exc_info.value.wavelet_index_ho == tables.WaveletFilters.haar_with_shift assert exc_info.value.dwt_depth == 999 assert exc_info.value.dwt_depth_ho == 9999
def test_picture_not_allowed_to_change_between_fragments(self): fh1 = serialise_to_bytes( bitstream.FragmentHeader( fragment_slice_count=1, picture_number=1000, )) fh2 = serialise_to_bytes( bitstream.FragmentHeader( fragment_slice_count=1, picture_number=1001, )) state = bytes_to_state(fh1 + fh2) state["_last_picture_number"] = 1000 state["_last_picture_number_offset"] = (-1, 4) state["_picture_initial_fragment_offset"] = (-1, 0) state[ "picture_coding_mode"] = tables.PictureCodingModes.pictures_are_frames state["_num_pictures_in_sequence"] = 0 state["_fragment_slices_remaining"] = 1 state["fragment_slices_received"] = 0 state["slices_x"] = 1 state["slices_y"] = 1 decoder.fragment_header(state) with pytest.raises( decoder.PictureNumberChangedMidFragmentedPicture) as exc_info: decoder.fragment_header(state) assert exc_info.value.last_picture_number_offset == (-1, 4) assert exc_info.value.picture_number_offset == (len(fh1) + 4, 7) assert exc_info.value.last_picture_number == 1000 assert exc_info.value.picture_number == 1001
def test_byte_for_byte_identical(self): sh1 = serialise_to_bytes( bitstream.SequenceHeader( parse_parameters=bitstream.ParseParameters( major_version=1, profile=tables.Profiles.low_delay, ), )) sh2 = serialise_to_bytes( bitstream.SequenceHeader( parse_parameters=bitstream.ParseParameters(major_version=2), )) state = bytes_to_state(sh1 + sh1 + sh2) decoder.sequence_header(state) decoder.byte_align(state) decoder.sequence_header(state) decoder.byte_align(state) with pytest.raises( decoder.SequenceHeaderChangedMidSequence) as exc_info: decoder.sequence_header(state) assert exc_info.value.last_sequence_header_offset == len(sh1) assert exc_info.value.last_sequence_header_bytes == sh1 assert exc_info.value.this_sequence_header_offset == len(sh1) * 2 assert exc_info.value.this_sequence_header_bytes == sh2
def test_whole_picture(parse_code): # A sanity check which runs picture decoding for whole pictures and makes # sure nothing crashes # Serialise a sample stream sh = bitstream.SequenceHeader( video_parameters=bitstream.SourceParameters( frame_size=bitstream.FrameSize( # Don't waste time on full-sized frames custom_dimensions_flag=True, frame_width=4, frame_height=4, ), clean_area=bitstream.CleanArea( custom_clean_area_flag=True, clean_width=4, clean_height=4, ), ), ) serialisation_state = State() sh_bytes = serialise_to_bytes(sh, serialisation_state) serialisation_state["parse_code"] = parse_code pic_bytes = serialise_to_bytes(bitstream.PictureParse(), serialisation_state) # Check it is parsed without failiures state = bytes_to_state(sh_bytes + pic_bytes) state["_num_pictures_in_sequence"] = 0 decoder.sequence_header(state) state["parse_code"] = parse_code decoder.picture_parse(state)
def test_wavelet_index_ho_must_be_valid(self): state = bytes_to_state( serialise_to_bytes( bitstream.ExtendedTransformParameters( asym_transform_index_flag=True, wavelet_index_ho=tables.WaveletFilters.haar_no_shift, ), )) state["wavelet_index"] = tables.WaveletFilters.haar_no_shift state["wavelet_index_ho"] = tables.WaveletFilters.haar_no_shift state["dwt_depth"] = 0 state["dwt_depth_ho"] = 0 decoder.extended_transform_parameters(state) state = bytes_to_state( serialise_to_bytes( bitstream.ExtendedTransformParameters( asym_transform_index_flag=True, wavelet_index_ho=9999, ), )) state["wavelet_index"] = tables.WaveletFilters.haar_no_shift state["wavelet_index_ho"] = tables.WaveletFilters.haar_no_shift state["dwt_depth"] = 0 state["dwt_depth_ho"] = 0 with pytest.raises(decoder.BadHOWaveletIndex) as exc_info: decoder.extended_transform_parameters(state) assert exc_info.value.wavelet_index_ho == 9999
def test_index_must_be_valid(self): state = bytes_to_state( serialise_to_bytes( bitstream.ColorMatrix( custom_color_matrix_flag=True, index=tables.PresetColorMatrices.hdtv, ), {}, {}, )) state["major_version"] = 3 decoder.color_matrix(state, {}) state = bytes_to_state( serialise_to_bytes( bitstream.ColorMatrix( custom_color_matrix_flag=True, index=9999, ), {}, {}, )) state["major_version"] = 3 with pytest.raises(decoder.BadPresetColorMatrix) as exc_info: decoder.color_matrix(state, {}) assert exc_info.value.index == 9999
def test_index_must_be_valid(self): state = bytes_to_state( serialise_to_bytes( bitstream.TransferFunction( custom_transfer_function_flag=True, index=tables.PresetTransferFunctions.hybrid_log_gamma, ), {}, {}, )) state["major_version"] = 3 decoder.transfer_function(state, {}) state = bytes_to_state( serialise_to_bytes( bitstream.TransferFunction( custom_transfer_function_flag=True, index=9999, ), {}, {}, )) state["major_version"] = 3 with pytest.raises(decoder.BadPresetTransferFunction) as exc_info: decoder.transfer_function(state, {}) assert exc_info.value.index == 9999
def test_index_must_be_valid(self): state = bytes_to_state( serialise_to_bytes( bitstream.PixelAspectRatio( custom_pixel_aspect_ratio_flag=True, index=tables.PresetPixelAspectRatios.ratio_1_1, ), {}, {}, )) state["major_version"] = 3 decoder.pixel_aspect_ratio(state, {}) state = bytes_to_state( serialise_to_bytes( bitstream.PixelAspectRatio( custom_pixel_aspect_ratio_flag=True, index=9999, ), {}, {}, )) state["major_version"] = 3 with pytest.raises(decoder.BadPresetPixelAspectRatio) as exc_info: decoder.pixel_aspect_ratio(state, {}) assert exc_info.value.index == 9999
def test_color_diff_sampling_format_index_must_be_valid(): state = bytes_to_state( serialise_to_bytes( bitstream.ColorDiffSamplingFormat( custom_color_diff_format_flag=True, color_diff_format_index=tables.ColorDifferenceSamplingFormats. color_4_4_4, ), {}, {}, )) decoder.color_diff_sampling_format(state, {}) state = bytes_to_state( serialise_to_bytes( bitstream.ColorDiffSamplingFormat( custom_color_diff_format_flag=True, color_diff_format_index=9999, ), {}, {}, )) with pytest.raises(decoder.BadColorDifferenceSamplingFormat) as exc_info: decoder.color_diff_sampling_format(state, {}) assert exc_info.value.color_diff_format_index == 9999
def test_level_must_be_valid(self): state = bytes_to_state( serialise_to_bytes( bitstream.ParseParameters(level=tables.Levels.unconstrained))) decoder.parse_parameters(state) state = bytes_to_state( serialise_to_bytes(bitstream.ParseParameters(level=9999))) with pytest.raises(decoder.BadLevel) as exc_info: decoder.parse_parameters(state) assert exc_info.value.level == 9999
def test_profile_must_be_valid(self): state = bytes_to_state( serialise_to_bytes( bitstream.ParseParameters( profile=tables.Profiles.high_quality))) decoder.parse_parameters(state) state = bytes_to_state( serialise_to_bytes(bitstream.ParseParameters(profile=9999))) with pytest.raises(decoder.BadProfile) as exc_info: decoder.parse_parameters(state) assert exc_info.value.profile == 9999
def test_custom_clean_area(via_custom_clean_width, clean_width, clean_height, left_offset, top_offset, exp_fail): frame_width = 1920 frame_height = 1080 if via_custom_clean_width: video_parameters = { "frame_width": frame_width, "frame_height": frame_height, } state = bytes_to_state( serialise_to_bytes( bitstream.CleanArea( custom_clean_area_flag=True, clean_width=clean_width, clean_height=clean_height, left_offset=left_offset, top_offset=top_offset, ), {}, video_parameters, )) state["major_version"] = 3 else: video_parameters = { "frame_width": frame_width, "frame_height": frame_height, "clean_width": clean_width, "clean_height": clean_height, "left_offset": left_offset, "top_offset": top_offset, } state = bytes_to_state( serialise_to_bytes( bitstream.CleanArea(custom_clean_area_flag=False, ), {}, video_parameters, )) state["major_version"] = 3 if exp_fail: with pytest.raises(decoder.CleanAreaOutOfRange) as exc_info: decoder.clean_area(state, video_parameters) assert exc_info.value.clean_width == clean_width assert exc_info.value.clean_height == clean_height assert exc_info.value.left_offset == left_offset assert exc_info.value.top_offset == top_offset assert exc_info.value.frame_width == frame_width assert exc_info.value.frame_height == frame_height else: decoder.clean_area(state, video_parameters)
def test_profile_version_restriction(self): # A sequence with no pictures but (incorrectly) major_version 1 and # profile high quality. seq = bitstream.Sequence(data_units=[ bitstream.DataUnit( parse_info=bitstream.ParseInfo( parse_code=tables.ParseCodes.sequence_header, ), sequence_header=bitstream.SequenceHeader( parse_parameters=bitstream.ParseParameters( major_version=1, profile=tables.Profiles.high_quality, ), video_parameters=bitstream.SourceParameters( frame_size=bitstream.FrameSize( # Don't waste time on full-sized frames custom_dimensions_flag=True, frame_width=4, frame_height=4, ), clean_area=bitstream.CleanArea( custom_clean_area_flag=True, clean_width=4, clean_height=4, ), ), ), ), bitstream.DataUnit(parse_info=bitstream.ParseInfo( parse_code=tables.ParseCodes.end_of_sequence, ), ), ]) populate_parse_offsets(seq) state = bytes_to_state(serialise_to_bytes(seq)) with pytest.raises(decoder.ProfileNotSupportedByVersion): decoder.parse_stream(state)
def test_must_not_have_too_many_slices( self, fragment_slice_count, fragment_slices_remaining, exp_fail, ): state = bytes_to_state( serialise_to_bytes( bitstream.FragmentHeader( fragment_slice_count=fragment_slice_count, picture_number=0, ))) state["_picture_initial_fragment_offset"] = (-1, 7) state["_fragment_slices_remaining"] = fragment_slices_remaining state["fragment_slices_received"] = 0 state["_last_picture_number"] = 0 # Only required in non-failing cases state["slices_x"] = 1 state["slices_y"] = 1 if exp_fail: with pytest.raises( decoder.TooManySlicesInFragmentedPicture) as exc_info: decoder.fragment_header(state) assert exc_info.value.initial_fragment_offset == (-1, 7) assert exc_info.value.this_fragment_offset == (0, 7) assert exc_info.value.fragment_slices_received == 0 assert exc_info.value.fragment_slices_remaining == fragment_slices_remaining assert exc_info.value.fragment_slice_count == fragment_slice_count else: decoder.fragment_header(state)
def test_signal_range_excursion_must_be_valid(luma_excursion, color_diff_excursion, exp_component): state = bytes_to_state( serialise_to_bytes( bitstream.SignalRange( custom_signal_range_flag=True, index=0, luma_offset=0, luma_excursion=luma_excursion, color_diff_offset=0, color_diff_excursion=color_diff_excursion, ), {}, {}, )) state["major_version"] = 3 if exp_component is None: # Should not fail decoder.signal_range(state, {}) else: with pytest.raises(decoder.BadCustomSignalExcursion) as exc_info: decoder.signal_range(state, {}) assert exc_info.value.component_type_name == exp_component
def test_bad_parse_code(self): state = bytes_to_state( serialise_to_bytes(bitstream.ParseInfo(parse_code=0x11))) state["_generic_sequence_matcher"] = Matcher(".*") with pytest.raises(decoder.BadParseCode) as exc_info: decoder.parse_info(state) assert exc_info.value.parse_code == 0x11
def test_unsupported_picture_coding_mode(self): state = bytes_to_state( serialise_to_bytes( bitstream.SequenceHeader(picture_coding_mode=2))) with pytest.raises(decoder.BadPictureCodingMode) as exc_info: decoder.sequence_header(state) assert exc_info.value.picture_coding_mode == 2
def test_first_fragment_must_have_slice_count_zero( self, fragment_slice_count, fragment_slices_remaining, exp_fail, ): state = bytes_to_state( serialise_to_bytes( bitstream.FragmentHeader( fragment_slice_count=fragment_slice_count, ))) state["_picture_initial_fragment_offset"] = (-1, 7) state["fragment_slices_received"] = 0 state["_fragment_slices_remaining"] = fragment_slices_remaining # Required only when not failing state["_num_pictures_in_sequence"] = 0 state[ "picture_coding_mode"] = tables.PictureCodingModes.pictures_are_frames if exp_fail: with pytest.raises(decoder.FragmentedPictureRestarted) as exc_info: decoder.fragment_header(state) assert exc_info.value.initial_fragment_offset == (-1, 7) assert exc_info.value.this_fragment_offset == (0, 7) assert exc_info.value.fragment_slices_received == 0 assert exc_info.value.fragment_slices_remaining == fragment_slices_remaining else: decoder.fragment_header(state)
def test_supported_picture_coding_mode(self): state = bytes_to_state( serialise_to_bytes( bitstream.SequenceHeader( picture_coding_mode=tables.PictureCodingModes. pictures_are_frames))) decoder.sequence_header(state)
def sh_data_unit_bytes(self, sh_bytes, sh_parse_offset): # parse_info + sequence header return (serialise_to_bytes( bitstream.ParseInfo( parse_code=tables.ParseCodes.sequence_header, next_parse_offset=sh_parse_offset, )) + sh_bytes)
def test_unsupported_base_video_format(self): state = bytes_to_state( serialise_to_bytes( bitstream.SequenceHeader(base_video_format=9999))) with pytest.raises(decoder.BadBaseVideoFormat) as exc_info: decoder.sequence_header(state) assert exc_info.value.base_video_format == 9999
def test_non_empty_sequence(self): sh = bitstream.SequenceHeader() seq = bitstream.Sequence(data_units=[ bitstream.DataUnit( parse_info=bitstream.ParseInfo( parse_code=tables.ParseCodes.sequence_header, ), sequence_header=sh, ), bitstream.DataUnit( parse_info=bitstream.ParseInfo( parse_code=tables.ParseCodes.sequence_header, ), sequence_header=sh, ), bitstream.DataUnit(parse_info=bitstream.ParseInfo( parse_code=tables.ParseCodes.end_of_sequence, ), ), ]) sh_length = len(serialise_to_bytes(sh)) populate_parse_offsets(seq) assert seq["data_units"][0]["parse_info"]["next_parse_offset"] == ( tables.PARSE_INFO_HEADER_BYTES + sh_length) assert seq["data_units"][0]["parse_info"]["previous_parse_offset"] == 0 assert seq["data_units"][1]["parse_info"]["next_parse_offset"] == ( tables.PARSE_INFO_HEADER_BYTES + sh_length) assert seq["data_units"][1]["parse_info"]["previous_parse_offset"] == ( tables.PARSE_INFO_HEADER_BYTES + sh_length) assert seq["data_units"][2]["parse_info"]["next_parse_offset"] == 0 assert seq["data_units"][2]["parse_info"]["previous_parse_offset"] == ( tables.PARSE_INFO_HEADER_BYTES + sh_length)
def test_value_ranges_restricted(self, dwt_depth, dwt_depth_ho, matrix, exp_fail_value): state = { "wavelet_index": tables.WaveletFilters.haar_no_shift, "wavelet_index_ho": tables.WaveletFilters.haar_no_shift, "dwt_depth": dwt_depth, "dwt_depth_ho": dwt_depth_ho, "_level_constrained_values": { "level": tables.Levels.sub_sd }, } state.update( bytes_to_state( serialise_to_bytes( bitstream.QuantMatrix( custom_quant_matrix=True, quant_matrix=matrix, ), state.copy(), ))) if exp_fail_value is not None: with pytest.raises(decoder.QuantisationMatrixValueNotAllowedInLevel ) as exc_info: decoder.quant_matrix(state) assert exc_info.value.value == exp_fail_value assert exc_info.value.allowed_values == ValueSet((0, 127)) assert exc_info.value.level_constrained_values == { "level": tables.Levels.sub_sd, "custom_quant_matrix": True, } else: decoder.quant_matrix(state)
def test_initialize_wavelet_data(dwt_depth, dwt_depth_ho): # This test attempts to ensure that initialize_wavelet_data produces arrays # of the correct size etc. This is done using an all-zeros hq_slice to zero out these # arrays (which are initialised to 'None'). If all values are zero after # this step (and nothing crashes with an out-of-bounds error) this function # should be correct. state = { "parse_code": tables.ParseCodes.high_quality_picture, "slices_x": 1, "slices_y": 1, "luma_width": 20, "luma_height": 10, "color_diff_width": 10, "color_diff_height": 5, "wavelet_index": tables.WaveletFilters.haar_no_shift, "wavelet_index_ho": tables.WaveletFilters.haar_no_shift, "dwt_depth": dwt_depth, "dwt_depth_ho": dwt_depth_ho, "slice_prefix_bytes": 0, "slice_size_scaler": 1, "quant_matrix": tables.QUANTISATION_MATRICES[( tables.WaveletFilters.haar_no_shift, tables.WaveletFilters.haar_no_shift, dwt_depth, dwt_depth_ho, )], } state.update( bytes_to_state( serialise_to_bytes( bitstream.TransformData(), state.copy(), ))) decoder.transform_data(state) for transform in ["y_transform", "c1_transform", "c2_transform"]: for level_data in state[transform].values(): for orientation_data in level_data.values(): for row in orientation_data: for value in row: assert value == 0
def test_allowed_zero_next_parse_offset_for_pictures(self, parse_code): state = bytes_to_state( serialise_to_bytes( bitstream.ParseInfo( parse_code=parse_code, next_parse_offset=0, ))) state["major_version"] = 3 state["_generic_sequence_matcher"] = Matcher(".*") decoder.parse_info(state)
def test_major_version_must_be_at_least_one(self): state = bytes_to_state( serialise_to_bytes( bitstream.ParseParameters( level=0, profile=0, major_version=0, minor_version=0, ))) with pytest.raises(decoder.MajorVersionTooLow): decoder.parse_parameters(state)
def test_minor_version_must_be_zero(self): state = bytes_to_state( serialise_to_bytes( bitstream.ParseParameters( level=0, profile=0, major_version=3, minor_version=1, ))) with pytest.raises(decoder.MinorVersionNotZero): decoder.parse_parameters(state)
def test_high_quality_profile_requires_version_two(self): state = bytes_to_state( serialise_to_bytes( bitstream.ParseParameters( level=0, profile=tables.Profiles.high_quality, major_version=1, minor_version=0, ))) with pytest.raises(decoder.ProfileNotSupportedByVersion): decoder.parse_parameters(state)