Introducción
DVBSTP (Digital Video Broadcasting - Stream Transfer Protocol) es un protocolo estándar desarrollado por el consorcio DVB para la distribución eficiente y fiable de flujos de datos de radiodifusión digital, como señales de televisión digital, radio digital y otros servicios multimedia.
DVBSTP se utiliza principalmente para la transmisión de datos en redes IP (Protocolo de Internet) sobre redes de transmisión asincrónica. Proporciona mecanismos para la gestión de errores, control de flujo y recuperación de datos para garantizar la integridad y calidad de los servicios de radiodifusión digital.
Se ha desarrollado un programa en Python que, basándose en la especificación pública ETSI TS 102 034 disecciona sus paquetes UDP.
Uso de DVBSTP Parser
Al recibirse los paquetes desde una dirección IP multicast, se especificará como primer parámetro la dirección IP y como segundo parámetro el puerto.
$ 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'...'
Código fuente
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