Ejemplo n.º 1
0
    def compute(sequence, algorithm, direction, L, D, packets):
        u"""
        This method will generate FEC packet's field by applying FEC algorithm to input packets.
        In case of error (e.g. bad version number) the method will abort filling fields and
        un-updated fields are set to their corresponding default value.

        :param sequence: Sequence number of computed FEC packet
        :type sequence: int
        :param algorithm: Name of algorithm used to compute payload recovery from packets payload
        :type algorithm: str
        :param direction: Direction (column or row) of computed FEC packet (see RFC to understand)
        :type direction: str
        :param L: Horizontal size of the FEC matrix (columns)
        :type L: int
        :param D: Vertical size of the FEC matrix (rows)
        :type D: int
        :param packets: Array containing RTP packets to protect
        :type packets: array(RtPacket)

        **Example usage**

        Testing invalid input collection of packets:

        >>> from RtpPacket import RtpPacket
        >>> packets = [RtpPacket.create(10, 10, RtpPacket.MP2T_PT, 'a'), \
                       RtpPacket.create(22, 22, RtpPacket.MP2T_PT, 'b')]
        >>> fec = FecPacket.compute(1, FecPacket.XOR, FecPacket.COL, 2, 2, packets)
        Traceback (most recent call last):
            ...
        ValueError: One of the packets doesn't verify : sequence = snbase + i * offset, 0<i<na

        Testing valid input collection of packets:

        >>> packets = [RtpPacket.create(10, 10, RtpPacket.MP2T_PT, bytearray('gaga')),  \
                       RtpPacket.create(14, 14, RtpPacket.MP2T_PT, bytearray('salut')), \
                       RtpPacket.create(18, 18, RtpPacket.MP2T_PT, bytearray('12345')), \
                       RtpPacket.create(22, 22, RtpPacket.MP2T_PT, bytearray('robot'))]
        >>> fec = FecPacket.compute(2, FecPacket.XOR, FecPacket.COL, 4, 4, packets)
        >>> print(fec)
        errors                = []
        sequence              = 2
        algorithm             = XOR
        direction             = COL
        snbase                = 10
        offset                = 4
        na                    = 4
        L x D                 = 4 x 4
        payload type recovery = 0
        timestamp recovery    = 0
        length recovery       = 1
        payload recovery size = 5
        missing               = []
        >>> print(''.join('%02x:' % x for x in fec.payload_recovery))
        57:5d:5a:4f:35:

        Testing fec packet generation (based on source RTP packets):

        >>> from os import urandom
        >>> from random import randint
        >>> from RtpPacket import RtpPacket
        >>> L = 4
        >>> D = 5
        >>> OFF = 2
        >>> # Generate a [D][L] matrix of randomly generated RTP packets
        >>> matrix = [[RtpPacket.create(L * j + i, (L * j + i) * 100 + randint(0, 50), \
                      RtpPacket.MP2T_PT, bytearray(urandom(randint(50, 100)))) \
                      for i in range(L)] for j in range(D)]
        >>> assert(len(matrix) == D and len(matrix[0]) == L)
        >>> # Retrieve the OFF'th column of the matrix
        >>> expected_payload_type_recovery = 0
        >>> expected_timestamp_recovery = 0
        >>> expected_lenght_recovery = 0
        >>> expected_payload_recovery = bytearray(100)
        >>> packets = []
        >>> for i in range(D):
        ...     packet = matrix[i][OFF]
        ...     packets.append(packet)
        ...     # Compute expected recovery fields values
        ...     expected_payload_type_recovery ^= packet.payload_type
        ...     expected_timestamp_recovery ^= packet.timestamp
        ...     expected_lenght_recovery ^= packet.payload_size
        ...     for j in range(packet.payload_size):
        ...         expected_payload_recovery[j] ^= packet.payload[j]
        >>> fec = FecPacket.compute(15, FecPacket.XOR, FecPacket.COL, L, D, packets)
        >>> assert(fec.valid)
        >>> assert(fec.snbase == matrix[0][OFF].sequence == 2)
        >>> assert(fec.na == D and fec.offset == L)
        >>> assert(fec.payload_type_recovery == expected_payload_type_recovery)
        >>> assert(fec.timestamp_recovery == expected_timestamp_recovery)
        >>> assert(fec.length_recovery == expected_lenght_recovery)
        >>> for i in range(fec.payload_size):
        ...     if fec.payload_recovery[i] != expected_payload_recovery[i]:
        ...         print('Payload recovery test failed with i = ' + i)
        """
        # Fields default values
        fec = FecPacket()
        fec.sequence = sequence
        if not algorithm in FecPacket.ALGORITHM_RANGE:
            raise ValueError('algorithm is not a valid FEC algorithm')
        if not direction in FecPacket.DIRECTION_RANGE:
            raise ValueError('direction is not a valid FEC direction')
        fec.algorithm = algorithm
        fec.direction = direction
        if fec.direction == FecPacket.COL:
            fec.na = D
            fec.offset = L
        else:
            fec.na = L
            fec.offset = 1
        if fec.algorithm != FecPacket.XOR:
            raise NotImplementedError(FecPacket.ER_ALGORITHM)
        if len(packets) != fec.na:
            raise ValueError('packets must contain exactly %s packets' % fec.na)
        fec.snbase = packets[0].sequence
        # Detect maximum length of packets payload and check packets validity
        size = 0
        i = 0
        for packet in packets:
            if not packet.validMP2T:
                raise ValueError(FecPacket.ER_VALID_MP2T)
            if packet.sequence != (fec.snbase + i*fec.offset) % RtpPacket.S_MASK:
                raise ValueError(FecPacket.ER_SEQUENCE)
            size = max(size, packet.payload_size)
            i += 1
        # Create payload recovery field according to size/length
        fec.payload_recovery = bytearray(size)
        # Compute FEC packet's fields based on input packets
        for packet in packets:
            # Update (...) recovery fields by xor'ing corresponding fields of all packets
            fec.payload_type_recovery ^= packet.payload_type
            fec.timestamp_recovery ^= packet.timestamp
            fec.length_recovery ^= packet.payload_size
            # Update payload recovery by xor'ing all packets payload
            payload = packet.payload
            if len(packet.payload) < size:
                payload = payload + bytearray(size - len(packet.payload))
            fast_xor_inplace(fec.payload_recovery, payload)
            # NUMPY fec.payload_recovery = bytearray(numpy.bitwise_xor(fec.payload_recovery, payload))
            # XOR LOOP for i in xrange(min(size, len(packet.payload))):
            # XOR LOOP     fec.payload_recovery[i] ^= packet.payload[i]
        return fec
Ejemplo n.º 2
0
    print('Xor benchmark')

    import os
    from time import time

    a1 = bytearray(os.urandom(1024 * 1024 * 2))
    a2 = a1[:]
    a3 = a1[:]
    a4 = a1[:]
    a5 = a1[:]
    b = bytearray(os.urandom(len(a1)))

    t0 = time()
    xor_inplace_loop(a1, b)
    t1 = time()
    a2 = xor_list_comprehension(a2, b)
    t2 = time()
    a3 = numpy_xor(a3, b)
    t3 = time()
    fast_xor_inplace(a4, b)
    t4 = time()

    for i in xrange(len(a1)):
        if a1[i] != a2[i] or a1[i] != a3[i] or a1[i] != a4[i] or a1[i] != a5[i]:
            print(i)

    print('function xor_inplace_loop takes %f' % (t1 - t0))
    print('function xor_list_comprehension takes %f' % (t2 - t1))
    print('function numpy.bitwise_xor takes %f' % (t3 - t2))
    print('function fastxor.fast_xor_inplace takes %f' % (t4 - t3))
Ejemplo n.º 3
0
    def compute(cls, sequence, algorithm, direction, L, D, packets):  # pylint:disable=invalid-name
        """
        This method will generate FEC packet's field by applying FEC algorithm to input packets.
        In case of error (e.g. bad version number) the method will abort filling fields and
        un-updated fields are set to their corresponding default value.

        :param sequence: Sequence number of computed FEC packet
        :type sequence: int
        :param algorithm: Name of algorithm used to compute payload recovery from packets payload
        :type algorithm: str
        :param direction: Direction (column or row) of computed FEC packet (see RFC to understand)
        :type direction: str
        :param L: Horizontal size of the FEC matrix (columns)
        :type L: int
        :param D: Vertical size of the FEC matrix (rows)
        :type D: int
        :param packets: Array containing RTP packets to protect
        :type packets: array(RtPacket)

        **Example usage**

        Testing invalid input collection of packets:

        >>> from pytoolbox.network.rtp import RtpPacket
        >>> packets = [
        ...     RtpPacket.create(10, 10, RtpPacket.MP2T_PT, 'a'),
        ...     RtpPacket.create(22, 22, RtpPacket.MP2T_PT, 'b')
        ... ]
        >>> fec = FecPacket.compute(1, FecPacket.XOR, FecPacket.COL, 2, 2, packets)
        Traceback (most recent call last):
            ...
        ValueError: One of the packets doesn't verify : sequence = snbase + i * offset, 0<i<na

        Testing valid input collection of packets:

        >>> packets = [
        ...     RtpPacket.create(10, 10, RtpPacket.MP2T_PT, bytearray('gaga', 'utf-8')),
        ...     RtpPacket.create(14, 14, RtpPacket.MP2T_PT, bytearray('salut', 'utf-8')),
        ...     RtpPacket.create(18, 18, RtpPacket.MP2T_PT, bytearray('12345', 'utf-8')),
        ...     RtpPacket.create(22, 22, RtpPacket.MP2T_PT, bytearray('robot', 'utf-8'))
        ... ]
        >>> fec = FecPacket.compute(2, FecPacket.XOR, FecPacket.COL, 4, 4, packets)
        >>> print(fec)
        errors                = []
        sequence              = 2
        algorithm             = XOR
        direction             = COL
        snbase                = 10
        offset                = 4
        na                    = 4
        L x D                 = 4 x 4
        payload type recovery = 0
        timestamp recovery    = 0
        length recovery       = 1
        payload recovery size = 5
        missing               = []
        >>> print(''.join('%02x:' % x for x in fec.payload_recovery))
        57:5d:5a:4f:35:

        Testing fec packet generation (based on source RTP packets):

        >>> from os import urandom
        >>> from random import randint
        >>> from pytoolbox.network.rtp import RtpPacket
        >>> L = 4
        >>> D = 5
        >>> OFF = 2
        >>> # Generate a [D][L] matrix of randomly generated RTP packets
        >>> matrix = [
        ...     [
        ...         RtpPacket.create(L * j + i, (L * j + i) * 100 + randint(0, 50),
        ...         RtpPacket.MP2T_PT, bytearray(urandom(randint(50, 100))))
        ...         for i in range(L)
        ...     ]
        ...     for j in range(D)
        ... ]
        >>> len(matrix)  # D
        5
        >>> len(matrix[0])  # L
        4

        Retrieve the OFF'th column of the matrix:

        >>> expected_payload_type_recovery = 0
        >>> expected_timestamp_recovery = 0
        >>> expected_lenght_recovery = 0
        >>> expected_payload_recovery = bytearray(100)
        >>> packets = []
        >>> for i in range(D):
        ...     packet = matrix[i][OFF]
        ...     packets.append(packet)
        ...     # Compute expected recovery fields values
        ...     expected_payload_type_recovery ^= packet.payload_type
        ...     expected_timestamp_recovery ^= packet.timestamp
        ...     expected_lenght_recovery ^= packet.payload_size
        ...     for j in range(packet.payload_size):
        ...         expected_payload_recovery[j] ^= packet.payload[j]
        >>> fec = FecPacket.compute(15, FecPacket.XOR, FecPacket.COL, L, D, packets)
        >>> fec.valid
        True
        >>> fec.snbase
        2
        >>> matrix[0][OFF].sequence
        2
        >>> fec.na  # D
        5
        >>> fec.offset  # L
        4
        >>> assert fec.payload_type_recovery == expected_payload_type_recovery
        >>> assert fec.timestamp_recovery == expected_timestamp_recovery
        >>> assert fec.length_recovery == expected_lenght_recovery
        >>> for i in range(fec.payload_size):
        ...     if fec.payload_recovery[i] != expected_payload_recovery[i]:
        ...         print('Payload recovery test failed with i = ' + i)
        """
        # Fields default values
        fec = cls()
        fec.sequence = sequence
        if algorithm not in cls.ALGORITHM_RANGE:
            raise ValueError('algorithm is not a valid FEC algorithm')
        if direction not in cls.DIRECTION_RANGE:
            raise ValueError('direction is not a valid FEC direction')
        fec.algorithm = algorithm
        fec.direction = direction
        if fec.direction == cls.COL:
            fec.na = D
            fec.offset = L
        else:
            fec.na = L
            fec.offset = 1
        if fec.algorithm != cls.XOR:
            raise NotImplementedError(cls.ER_ALGORITHM)
        if len(packets) != fec.na:
            raise ValueError(f'packets must contain exactly {fec.na} packets')
        fec.snbase = packets[0].sequence

        # Detect maximum length of packets payload and check packets validity
        size = i = 0
        for packet in packets:
            if not packet.validMP2T:
                raise ValueError(cls.ER_VALID_MP2T)
            if packet.sequence != (fec.snbase +
                                   i * fec.offset) & RtpPacket.S_MASK:
                raise ValueError(cls.ER_SEQUENCE)

            size = max(size, packet.payload_size)
            i += 1

        # Create payload recovery field according to size/length
        fec.payload_recovery = bytearray(size)

        # Compute FEC packet's fields based on input packets
        for packet in packets:

            # Update (...) recovery fields by xor'ing corresponding fields of all packets
            fec.payload_type_recovery ^= packet.payload_type
            fec.timestamp_recovery ^= packet.timestamp
            fec.length_recovery ^= packet.payload_size

            # Update payload recovery by xor'ing all packets payload
            payload = packet.payload
            if len(packet.payload) < size:
                payload = payload + bytearray(size - len(packet.payload))

            fast_xor_inplace(fec.payload_recovery, payload)
            # NUMPY fec.payload_recovery = bytearray(
            #     numpy.bitwise_xor(fec.payload_recovery, payload))
            # XOR LOOP for i in xrange(min(size, len(packet.payload))):
            # XOR LOOP     fec.payload_recovery[i] ^= packet.payload[i]
        return fec
Ejemplo n.º 4
0
    import os
    from time import time

    a1 = bytearray(os.urandom(1024*1024*2))
    a2 = a1[:]
    a3 = a1[:]
    a4 = a1[:]
    a5 = a1[:]
    b = bytearray(os.urandom(len(a1)))

    t0 = time()
    xor_inplace_loop(a1, b)
    t1 = time()
    a2 = xor_list_comprehension(a2, b)
    t2 = time()
    a3 = numpy_xor(a3, b)
    t3 = time()
    fast_xor_inplace(a4, b)
    t4 = time()

    for i in xrange(len(a1)):
        if a1[i] != a2[i] or a1[i] != a3[i] or a1[i] != a4[i] or a1[i] != a5[i]:
            print(i)

    print('function xor_inplace_loop takes %f' % (t1-t0))
    print('function xor_list_comprehension takes %f' % (t2-t1))
    print('function numpy.bitwise_xor takes %f' % (t3-t2))
    print('function fastxor.fast_xor_inplace takes %f' % (t4-t3))