Introduction️
DVBSTP (Digital Video Broadcasting - Stream Transfer Protocol) is a standard protocol developed by the DVB consortium for the efficient and reliable distribution of broadcast digital data streams, such as digital television signals, digital radio and other multimedia services.️
DVBSTP is mainly used for transmitting data in IP (Internet Protocol) networks over asynchronous transmission networks. It provides mechanisms for error management, flow control and data recovery to ensure the integrity and quality of digital broadcasting services.️
A Python program has been developed that, based on the public specification ETSI TS 102 034 dissects its UDP packets.️
DVBSTP Parser usage.️
When packets are received from a multicast IP address, the IP address will be specified as the first parameter and the port number as the second parameter.️
$ python dvb_stp_parser.py 239.0.0.1 22222
DVBSTP Message n1
Protocol Version: [00] -> IPv4 packet structure
Reserved: [000] -> Good
Encryption: [00] -> Not encrypted
CRC flag: [0] -> 32-bit CRC not present at the end of the packet
Total segment size: [000000010100000000000000] -> 81920 bytes
Payload ID: [00000000] -> 0
Segment ID: [0000000000000000] -> 0
Segment version: [00000010] -> 2
Section number: [000000000000] -> 0
Last section number: [000000000000] -> 0
Compression: [000] -> No Compression / Total Segment Size = Transmitted Size
ProviderID Flag: [0] -> Field not present
Private Header Length: [0110] -> 6 32-bit words -> 24.0 bytes
Private Header Data: [...] -> b'...'
Source code️
from bitstring import ConstBitStream
import socket
import struct
import sys
def setup_socket(ip, port):
multicast_group = ip
server_address = ('', port)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(server_address)
group = socket.inet_aton(multicast_group)
mreq = struct.pack('=4sl', group, socket.INADDR_ANY)
sock.setsockopt(
socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
mreq)
return sock
def version_text(field):
if field == '00':
return 'IPv4 packet structure'
elif field == '01':
return 'IPv6 packet structure'
return 'Not defined'
def reserved_text(field):
if field == '000':
return 'Good'
return 'Error'
def encryption_text(field):
if field == '00':
return 'Not encrypted'
return 'Maybe encrypted'
def crc_flag_text(field):
if field == '1':
return '32-bit CRC present at the end of the packet'
return '32-bit CRC not present at the end of the packet'
def compression_text(field):
if field == '000':
return 'No Compression / Total Segment Size = Transmitted Size'
elif field == '001':
return 'BiM / Total Segment Size = Transmitted Size'
elif field == '010':
return 'GZIP / Total Segment Size = Transmitted Size'
elif field == '110':
return 'For ITU-T use / Total Segment Size = Transmitted Size'
elif field == '111':
return 'User Private / Total Segment Size = User Defined'
return 'Reserved'
def providerid_flag_text(field):
if field == '1':
return 'Field present'
return 'Field not present'
def packet_text(data):
text = 'DVBSTP Message n' + str(i) + '\n'
# text = text + '\tRaw: ' + str(data) + '\n'
bits = ConstBitStream(data)
version = bits.read('bin:2')
text = text + '\tProtocol Version: ' + '[' + version + '] -> ' + version_text(version) + '\n'
reserved = bits.read('bin:3')
text = text + '\tReserved: ' + '[' + reserved + '] -> ' + reserved_text(reserved) + '\n'
encryption = bits.read('bin:2')
text = text + '\tEncryption: ' + '[' + encryption + '] -> ' + encryption_text(encryption) + '\n'
crc_flag = bits.read('bin:1')
text = text + '\tCRC flag: ' + '[' + crc_flag + '] -> ' + crc_flag_text(crc_flag) + '\n'
total_segment_size = bits.peek('bin:24')
text = text + '\tTotal segment size: ' + '[' + total_segment_size + '] -> ' + str(bits.read('int:24')) + ' bytes\n'
payload_id = bits.peek('bin:8')
text = text + '\tPayload ID: ' + '[' + payload_id + '] -> ' + str(bits.read('int:8')) + '\n'
segment_id = bits.peek('bin:16')
text = text + '\tSegment ID: ' + '[' + segment_id + '] -> ' + str(bits.read('int:16')) + '\n'
segment_version = bits.peek('bin:8')
text = text + '\tSegment version: ' + '[' + segment_version + '] -> ' + str(bits.read('int:8')) + '\n'
section_number = bits.peek('bin:12')
text = text + '\tSection number: ' + '[' + section_number + '] -> ' + str(bits.read('int:12')) + '\n'
last_section_number = bits.peek('bin:12')
text = text + '\tLast section number: ' + '[' + last_section_number + '] -> ' + str(bits.read('int:12')) + '\n'
compression = bits.read('bin:3')
text = text + '\tCompression: ' + '[' + compression + '] -> ' + compression_text(compression) + '\n'
providerid_flag = bits.read('bin:1')
text = text + '\tProviderID Flag: ' + '[' + providerid_flag + '] -> ' + providerid_flag_text(providerid_flag) + '\n'
private_header_length = bits.peek('bin:4')
private_header_length_bytes = (bits.peek('int:4') * 32) / 8
text = text + '\tPrivate Header Length: ' + '[' + private_header_length + '] -> ' + str(bits.read('int:4')) + ' 32-bit words -> '+ str(private_header_length_bytes) + ' bytes\n'
if providerid_flag == '1':
serviceprovider_id = bits.read('bin:32')
text = text + '\tServiceProvider ID: ' + '[' + serviceprovider_id + ']\n'
if private_header_length != '0000':
private_header_data = bits.peek('bin:' + str(int(private_header_length_bytes) * 8))
text = text + '\tPrivate Header Data: ' + '[' + private_header_data + '] -> ' + str(bits.peek('bytes:' + str(int(private_header_length_bytes)))) + '\n'
return text
sock = setup_socket(sys.argv[1], int(sys.argv[2]))
i = 1
while True:
data, addr = sock.recvfrom(1500)
print(packet_text(data))
i = i + 1