Beispiel #1
0
 def test_non_match(self, regex, sequence):
     m = Matcher(regex)
     for i, symbol in enumerate(sequence):
         if i == len(sequence) - 1:
             assert m.match_symbol(symbol) is False
         else:
             assert m.match_symbol(symbol) is True
Beispiel #2
0
    def test_incomplete_match(self):
        m = Matcher("foo bar+")

        assert not m.is_complete()
        assert m.match_symbol("foo")
        assert not m.is_complete()
        assert m.match_symbol("bar")
        assert m.is_complete()
        assert m.match_symbol("bar")
        assert m.is_complete()
Beispiel #3
0
 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
Beispiel #4
0
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"])
Beispiel #5
0
    def test_level_restricts_sequence(self):
        state = bytes_to_state(
            serialise_to_bytes(
                bitstream.ParseInfo(
                    parse_code=tables.ParseCodes.end_of_sequence, )))
        state["_generic_sequence_matcher"] = Matcher(".*")
        state["_level_sequence_matcher"] = Matcher("sequence_header")
        state["level"] = tables.Levels.unconstrained

        with pytest.raises(decoder.LevelInvalidSequence) as exc_info:
            decoder.parse_info(state)

        assert exc_info.value.parse_code is tables.ParseCodes.end_of_sequence
        assert exc_info.value.expected_parse_codes == [
            tables.ParseCodes.sequence_header
        ]
        assert exc_info.value.expected_end is False
        assert exc_info.value.level == tables.Levels.unconstrained
Beispiel #6
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)
Beispiel #7
0
 def test_never_allowed_invalid_offset(self, parse_code, next_parse_offset):
     state = bytes_to_state(
         serialise_to_bytes(
             bitstream.ParseInfo(
                 parse_code=parse_code,
                 next_parse_offset=next_parse_offset,
             )))
     state["_generic_sequence_matcher"] = Matcher(".*")
     with pytest.raises(decoder.InvalidNextParseOffset) as exc_info:
         decoder.parse_info(state)
     assert exc_info.value.next_parse_offset == next_parse_offset
Beispiel #8
0
 def test_not_allowed_zero_next_parse_offset_for_non_pictures(
         self, parse_code):
     state = bytes_to_state(
         serialise_to_bytes(
             bitstream.ParseInfo(
                 parse_code=parse_code,
                 next_parse_offset=0,
             )))
     state["_generic_sequence_matcher"] = Matcher(".*")
     with pytest.raises(decoder.MissingNextParseOffset) as exc_info:
         decoder.parse_info(state)
     assert exc_info.value.parse_code == parse_code
Beispiel #9
0
 def test_non_zero_previous_parse_offset_for_start_of_sequence(self):
     state = bytes_to_state(
         serialise_to_bytes(
             bitstream.ParseInfo(
                 parse_code=tables.ParseCodes.end_of_sequence,
                 previous_parse_offset=1,
             )))
     state["_generic_sequence_matcher"] = Matcher(".*")
     with pytest.raises(decoder.NonZeroPreviousParseOffsetAtStartOfSequence
                        ) as exc_info:
         decoder.parse_info(state)
     assert exc_info.value.previous_parse_offset == 1
Beispiel #10
0
    def test_invalid_generic_sequence(self):
        state = bytes_to_state(
            serialise_to_bytes(
                bitstream.ParseInfo(
                    parse_code=tables.ParseCodes.end_of_sequence, )))
        state["_generic_sequence_matcher"] = Matcher("sequence_header")

        with pytest.raises(decoder.GenericInvalidSequence) as exc_info:
            decoder.parse_info(state)

        assert exc_info.value.parse_code is tables.ParseCodes.end_of_sequence
        assert exc_info.value.expected_parse_codes == [
            tables.ParseCodes.sequence_header
        ]
        assert exc_info.value.expected_end is False
Beispiel #11
0
def test_parse_code_in_sequence(regex, expected_parse_codes, expected_end):
    m = Matcher(regex)

    class CustomException(Exception):
        def __init__(
            self, parse_code, actual_expected_parse_codes, actual_expected_end, foo
        ):
            assert parse_code is ParseCodes.auxiliary_data
            assert set(actual_expected_parse_codes) == expected_parse_codes
            assert actual_expected_end == expected_end
            assert foo == "bar"

    with pytest.raises(CustomException):
        assert_parse_code_in_sequence(
            ParseCodes.auxiliary_data, m, CustomException, "bar"
        )
Beispiel #12
0
def test_parse_code_sequence_ended(regex, expected_parse_codes):
    m = Matcher(regex)

    class CustomException(Exception):
        def __init__(
            self, parse_code, actual_expected_parse_codes, actual_expected_end, foo
        ):
            assert parse_code is None
            if expected_parse_codes is None:
                assert actual_expected_parse_codes is None
            else:
                assert set(actual_expected_parse_codes) == expected_parse_codes
            assert actual_expected_end is False
            assert foo == "bar"

    with pytest.raises(CustomException):
        assert_parse_code_sequence_ended(m, CustomException, "bar")
Beispiel #13
0
    def test_profile_restricts_allowed_parse_codes(self, parse_code, allowed):
        state = bytes_to_state(
            serialise_to_bytes(
                bitstream.ParseInfo(
                    parse_code=parse_code,
                    next_parse_offset=tables.PARSE_INFO_HEADER_BYTES,
                )))
        state["_generic_sequence_matcher"] = Matcher(".*")
        state["profile"] = tables.Profiles.high_quality

        if allowed:
            decoder.parse_info(state)
        else:
            with pytest.raises(
                    decoder.ParseCodeNotAllowedInProfile) as exc_info:
                decoder.parse_info(state)
            assert exc_info.value.parse_code == tables.ParseCodes.low_delay_picture
            assert exc_info.value.profile == tables.Profiles.high_quality
Beispiel #14
0
    def test_inconsistent_next_parse_offset(self):
        state = bytes_to_state(
            serialise_to_bytes(
                bitstream.ParseInfo(
                    parse_code=tables.ParseCodes.padding_data,
                    next_parse_offset=tables.PARSE_INFO_HEADER_BYTES + 10,
                )) + b"\x00" * 9 +
            serialise_to_bytes(
                bitstream.ParseInfo(
                    parse_code=tables.ParseCodes.end_of_sequence,
                    previous_parse_offset=tables.PARSE_INFO_HEADER_BYTES + 9,
                )))
        state["_generic_sequence_matcher"] = Matcher(".*")

        decoder.parse_info(state)
        decoder.read_uint_lit(state, 9)
        with pytest.raises(decoder.InconsistentNextParseOffset) as exc_info:
            decoder.parse_info(state)

        assert exc_info.value.parse_info_offset == 0
        assert exc_info.value.next_parse_offset == tables.PARSE_INFO_HEADER_BYTES + 10
        assert exc_info.value.true_parse_offset == tables.PARSE_INFO_HEADER_BYTES + 9
Beispiel #15
0
def parse_sequence(state):
    """
    (10.4.1) Parse a complete VC-2 sequence.
    """
    reset_state(state)

    # (10.4.1) Check that the sequence starts with a sequence_header and ends
    # with and end_of_sequence.
    ## Begin not in spec
    state["_generic_sequence_matcher"] = Matcher("sequence_header .* end_of_sequence")
    ## End not in spec

    state["_num_pictures_in_sequence"] = 0  ## Not in spec
    state["_fragment_slices_remaining"] = 0  ## Not in spec

    parse_info(state)
    while not is_end_of_sequence(state):
        if is_seq_header(state):
            state["video_parameters"] = sequence_header(state)
        elif is_picture(state):
            # Errata: fragments under-specified in spec
            #
            # (14.2) Picture data units may not be interleaved with in-progress
            # fragmented pictures.
            ## Begin not in spec
            if state["_fragment_slices_remaining"] != 0:
                raise PictureInterleavedWithFragmentedPicture(
                    state["_picture_initial_fragment_offset"],
                    tell(state),
                    state["fragment_slices_received"],
                    state["_fragment_slices_remaining"],
                )
            ## End not in spec

            picture_parse(state)
            picture_decode(state)
        elif is_fragment(state):
            fragment_parse(state)
            if state["fragmented_picture_done"]:
                picture_decode(state)
        elif is_auxiliary_data(state):
            auxiliary_data(state)
        elif is_padding_data(state):
            padding(state)
        parse_info(state)

    # (10.4.1) and (C.3) Check sequence structure allowed to end at this point
    ## Begin not in spec
    assert_parse_code_sequence_ended(
        state["_generic_sequence_matcher"], GenericInvalidSequence
    )
    if "_level_sequence_matcher" in state:
        assert_parse_code_sequence_ended(
            state["_level_sequence_matcher"],
            LevelInvalidSequence,
            state["level"],
        )
    ## End not in spec

    # Errata: fragments under-specified in spec
    #
    # (14.2) Ensure that any fragmented picture has been received completely by
    # the end of the stream.
    ## Begin not in spec
    if state["_fragment_slices_remaining"] != 0:
        raise SequenceContainsIncompleteFragmentedPicture(
            state["_picture_initial_fragment_offset"],
            state["fragment_slices_received"],
            state["_fragment_slices_remaining"],
        )
    ## End not in spec

    # (10.4.3) When pictures are fields, a sequence should contain a whole
    # number of frames
    ## Begin not in spec
    if state["picture_coding_mode"] == PictureCodingModes.pictures_are_fields:
        if state["_num_pictures_in_sequence"] % 2 != 0:
            raise OddNumberOfFieldsInSequence(state["_num_pictures_in_sequence"])
    ## End not in spec

    # (11.2.2) Check that the major_version number used was the lowest which
    # would be permissible for the features actually used
    assert_major_version_is_minimal(state)  ## Not in spec
Beispiel #16
0
 def test_valid_next_symbols(self, regex, next_symbols):
     m = Matcher(regex)
     assert m.valid_next_symbols() == next_symbols
Beispiel #17
0
 def test_complete_matches(self, regex, sequence):
     m = Matcher(regex)
     for symbol in sequence:
         assert m.match_symbol(symbol) is True
     assert m.is_complete() is True