A Python UPnP Media Server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
4.2 KiB

  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2006-2007 John-Mark Gurney.
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. # 1. Redistributions of source code must retain the above copyright
  10. # notice, this list of conditions and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. # notice, this list of conditions and the following disclaimer in the
  13. # documentation and/or other materials provided with the distribution.
  14. #
  15. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16. # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  19. # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. # SUCH DAMAGE.
  26. #
  27. # $Id$
  28. #
  29. import sys
  30. sys.path.append('/Users/jgurney/p4/bktrau/info')
  31. import itertools
  32. import mpegts
  33. import sets
  34. import struct
  35. import sys
  36. def usage():
  37. print >>sys.stderr, 'Usage: %s <file> <pmtpid> <pid> ...' % sys.argv[0]
  38. sys.exit(1)
  39. def genpats(pmt, prognum):
  40. 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")
  41. patidx = 4 + 1 # TS header + pointer table
  42. BASEPAT[patidx + 8] = chr(prognum >> 8)
  43. BASEPAT[patidx + 9] = chr(prognum & 0xff)
  44. BASEPAT[patidx + 10] = chr(0xe0 | ((pmt >> 8) & 0x1f))
  45. BASEPAT[patidx + 11] = chr(pmt & 0xff)
  46. newcrc = mpegts.psip_calc_crc32(''.join(BASEPAT[patidx:patidx + 12]))
  47. newcrc = map(lambda x, crc = newcrc: chr((crc >> (8 * (3 - x))) & 0xff), range(4))
  48. BASEPAT[patidx + 12:patidx + 16] = newcrc
  49. assert len(BASEPAT) == mpegts.TSPKTLEN
  50. ret = []
  51. # Generate continuity_counter
  52. old = ord(BASEPAT[3]) & 0xf0
  53. for i in range(16): # continuity
  54. BASEPAT[3] = chr(old | i)
  55. ret.append(''.join(BASEPAT))
  56. return ret
  57. def producets(inp, pmtpid, *pids):
  58. #print `inp`, `pmtpid`, `pids`
  59. # XXX - check if all pids are ints? in range?
  60. pids = sets.Set(pids)
  61. stream = mpegts.TSPStream(inp)
  62. didpmt = False
  63. for i in stream:
  64. frst = ord(i[1])
  65. # Get first and error bits for testing.
  66. pid = (frst & 0x1f) << 8 | ord(i[2])
  67. if frst & 0x80:
  68. continue
  69. elif pid == 0 and didpmt:
  70. yield pats.next()
  71. elif pid == pmtpid and frst & 0x40:
  72. if not didpmt:
  73. startpmt = 4
  74. if ((ord(i[3]) >> 4) & 0x3) == 0x3:
  75. # Has adaptation field
  76. startpmt += ord(i[startpmt]) + 1
  77. startpmt += ord(i[startpmt]) + 1
  78. assert i[startpmt] == '\x02', (startpmt, i[0:10])
  79. pats = itertools.cycle(genpats(pmtpid, struct.unpack('>H', i[startpmt + 3:startpmt + 5])[0]))
  80. yield pats.next()
  81. didpmt = True
  82. # XXX - we probably want to rewrite the PMT to only
  83. # include the pids we are sending.
  84. yield i
  85. elif pid in pids and didpmt:
  86. yield i
  87. def main():
  88. if len(sys.argv) < 3:
  89. usage()
  90. pmtpid = int(sys.argv[2])
  91. pids = map(int, sys.argv[3:])
  92. inp = open(sys.argv[1])
  93. out = sys.stdout
  94. producer = producets(inp, pmtpid, *pids)
  95. filter(lambda x: out.write(x), producer)
  96. if __name__ == '__main__':
  97. main()