tvheadend/support/iptv_gen.py
Adam Sutton 2d1bd1a254 mpegts: fix broken input handling for inputs with >1 active services..
This affects IPTV where there is only 1 input, if 2 services have the same PIDs
then both services were receiving each others packets and causing a mess!

I think later on I should really remove the transport list from the input and
have it on the mux? I think I did it this way to keep some things simpler, but
it's caused confusion here.

This should fix #1875.
2014-01-02 21:31:37 +00:00

162 lines
3.5 KiB
Python
Executable file

#!/usr/bin/env python
#
# Very simple looped file output via various formats for testing
# purposes
#
import os, sys, time
import socket, struct
from optparse import OptionParser
# Cmd line
optp = OptionParser()
optp.add_option('-p', '--protocol', default='udp')
optp.add_option('-d', '--debug', default=False, action='store_true')
optp.add_option('--port', default=9983, type='int')
optp.add_option('-i', '--ipaddr', default='127.0.0.1')
(opts,args) = optp.parse_args()
DEBUG = opts.debug
PKT_SIZE = 188 * 200
# Debug
def out ( pre, msg ):
print '%0.3f %s: %s' % (time.time(), pre, msg)
def debug ( msg ):
if DEBUG: out('D', msg)
def info ( msg ):
out('I', msg)
# Extract PCR
def extract_pcr ( tsb, pcr_pid ):
while len(tsb) >= 188:
pkt = map(ord, tsb[:16])
tsb = tsb[188:]
# TODO: TSB resync
# Errors
if pkt[0] != 0x47 or pkt[1] & 0x80:
continue
# PID
pid = ((pkt[1] & 0x1f) << 8) | pkt[2]
#print time.time()
#print '%04X %d' % (pid, pid)
#print ' '.join(map(lambda x: '%02X' % x, pkt))
# Not PCR
if pcr_pid and pcr_pid != pid:
continue
# PCR
if pkt[3] & 0x20 and pkt[4] and pkt[5] == 0x10:
#print 'PCR'
pcr = pkt[6] << 25
pcr = pcr + (pkt[7] << 17)
pcr = pcr + (pkt[8] << 9)
pcr = pcr + (pkt[9] << 1)
pcr = pcr + ((pkt[10] >> 7) & 0x1)
pcr_pid = pid
#print pcr
return (pcr_pid, pcr)
return (None, None)
# Loop file
def output_file ( path, cb ):
fp = open(path)
pcr_pid = None
pcr_last = None
pcr_init = None
pcr_rtc = None
while True:
if not fp:
info('open')
fp = open(path)
pcr_last = pcr_init = pcr_rtc = None
tsb = fp.read(PKT_SIZE)
# EOF
if len(tsb) != PKT_SIZE:
info('close')
fp.close()
fp = None
# Extract PCR
(pid, pcr) = extract_pcr(tsb, pcr_pid)
if pid:
pcr_pid = pid
debug('%d %d' % (pid, pcr))
# Wait
if pcr_init:
#debug('checking')
d = pcr - pcr_init
d = d / 90000.0
d = d + pcr_rtc
if d > time.time():
s = d - time.time()
debug('wait %f' % s)
time.sleep(s)
else:
print 'behind'
else:
pcr_init = pcr
pcr_rtc = time.time()
# Send
if cb: cb(tsb)
# Unicast
if opts.protocol == 'http':
pass
# Multicast
elif opts.protocol in [ 'udp', 'rtp' ]:
g = opts.ipaddr
p = opts.port
# Setup multicast connection
a = socket.getaddrinfo(g, None)[0]
s = socket.socket(a[0], socket.SOCK_DGRAM)
# Set Time-to-live (optional)
ttl = struct.pack('@i', 2)
if a[0] == socket.AF_INET: # IPv4
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
else:
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl)
# UDP output
def udp_out ( tsb ):
debug('send %d' % len(tsb))
try:
s.sendto(tsb, (a[4][0], p))
except: pass
debug('sent')
# RTP output
def rtp_out ( tsb ):
debug('send %d' % len(tsb))
rtp = '\x80\x21'
rtp = rtp + ('\x00' * 2) # TVH ignores seqnum
rtp = rtp + ('\x00' * 4) # TVH ignores timestamp
rtp = rtp + ('\x00' * 4) # TVH ignores SSRC
#rtp = rtp + ('\x00' * 4) # TVH ignores CSRC
# TODO: add CC and extension for testing
rtp = rtp + tsb
try:
s.sendto(rtp, (a[4][0], p))
except:
pass
debug('sent')
# Process
if opts.protocol == 'udp':
output_file(args[0], udp_out)
else:
output_file(args[0], rtp_out)