#!/usr/bin/env python # # Copyright 2006-2007 John-Mark Gurney. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $Id$ # import sys sys.path.append('/Users/jgurney/p4/bktrau/info') import itertools import mpegts import struct import sys def usage(): print >>sys.stderr, 'Usage: %s ...' % sys.argv[0] sys.exit(1) def genpats(pmt, prognum): BASEPAT = map(None, "\x47\x40\x00\x10\x00\x00\xb0\x0d\x00\x00\xc1\x00\x00\x00\x00\xe0\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff") patidx = 4 + 1 # TS header + pointer table BASEPAT[patidx + 8] = chr(prognum >> 8) BASEPAT[patidx + 9] = chr(prognum & 0xff) BASEPAT[patidx + 10] = chr(0xe0 | ((pmt >> 8) & 0x1f)) BASEPAT[patidx + 11] = chr(pmt & 0xff) newcrc = mpegts.psip_calc_crc32(''.join(BASEPAT[patidx:patidx + 12])) newcrc = map(lambda x, crc = newcrc: chr((crc >> (8 * (3 - x))) & 0xff), range(4)) BASEPAT[patidx + 12:patidx + 16] = newcrc assert len(BASEPAT) == mpegts.TSPKTLEN ret = [] # Generate continuity_counter old = ord(BASEPAT[3]) & 0xf0 for i in range(16): # continuity BASEPAT[3] = chr(old | i) ret.append(''.join(BASEPAT)) return ret def producets(inp, pmtpid, *pids): #print `inp`, `pmtpid`, `pids` # XXX - check if all pids are ints? in range? pids = sets.Set(pids) stream = mpegts.TSPStream(inp) didpmt = False for i in stream: frst = ord(i[1]) # Get first and error bits for testing. pid = (frst & 0x1f) << 8 | ord(i[2]) if frst & 0x80: continue elif pid == 0 and didpmt: yield pats.next() elif pid == pmtpid and frst & 0x40: if not didpmt: startpmt = 4 if ((ord(i[3]) >> 4) & 0x3) == 0x3: # Has adaptation field startpmt += ord(i[startpmt]) + 1 startpmt += ord(i[startpmt]) + 1 assert i[startpmt] == '\x02', (startpmt, i[0:10]) pats = itertools.cycle(genpats(pmtpid, struct.unpack('>H', i[startpmt + 3:startpmt + 5])[0])) yield pats.next() didpmt = True # XXX - we probably want to rewrite the PMT to only # include the pids we are sending. yield i elif pid in pids and didpmt: yield i def main(): if len(sys.argv) < 3: usage() pmtpid = int(sys.argv[2]) pids = map(int, sys.argv[3:]) inp = open(sys.argv[1]) out = sys.stdout producer = producets(inp, pmtpid, *pids) filter(lambda x: out.write(x), producer) if __name__ == '__main__': main()