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.

2061 lines
55 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 atschuff
  30. import itertools
  31. import os
  32. import sets
  33. import struct
  34. import time
  35. import traceback
  36. TSSYNC = '\x47'
  37. TSPKTLEN = 188
  38. READBLK = 1024
  39. def attribreprlist(obj, attrs):
  40. return map(lambda x, y = obj: '%s: %s' % (x, repr(getattr(y, x))),
  41. itertools.ifilter(lambda x, y = obj: hasattr(y, x), attrs))
  42. class UnReadSTR:
  43. def __init__(self, s):
  44. self.s = s
  45. self.pos = 0
  46. self._buf = []
  47. self._buftot = 0
  48. def __nonzero__(self):
  49. return self._buftot or self.pos < len(self.s)
  50. def tell(self):
  51. return self.pos - self._buftot
  52. def unread(self, buf):
  53. self._buf.append(buf)
  54. self._buftot += len(buf)
  55. def peek(self, size):
  56. r = self.read(size)
  57. self.unread(r)
  58. return r
  59. def sread(self, cnt = -1):
  60. oldpos = self.pos
  61. if cnt == -1:
  62. self.pos = len(self.s)
  63. return self.s[oldpos:]
  64. self.pos += cnt
  65. if self.pos > len(self.s):
  66. self.pos = len(self.s)
  67. return self.s[oldpos:self.pos]
  68. def read(self, size = None):
  69. if size is None and self._buf:
  70. ret = self._buf.pop()
  71. self._buftot -= len(ret)
  72. elif size is None:
  73. ret = self.sread()
  74. else:
  75. ret = []
  76. while size and self._buftot:
  77. ret.append(self._buf[-1][:size])
  78. l = len(ret[-1])
  79. if size > l:
  80. assert len(self._buf[-1]) == l
  81. self._buf.pop()
  82. else:
  83. self._buf[-1] = self._buf[-1][size:]
  84. self._buftot -= l
  85. size -= l
  86. if size:
  87. ret.append(self.sread(size))
  88. ret = ''.join(ret)
  89. return ret
  90. def DVDAudioFilter(itr, subchan):
  91. '''subchan should be in the range [0x80, 0x8f], this will filter out all other subchannels in that range that do not match subchan.'''
  92. assert subchan >= 0x80 and subchan <= 0x8f
  93. def checksubchan(pes, sc = subchan):
  94. if pes.stream_id != 0xbd:
  95. return False
  96. subchan = ord(pes.data[0])
  97. if subchan == sc or subchan < 0x80 or subchan > 0x8f:
  98. return True
  99. return False
  100. # XXX - I probably should mess w/ muxr so SCR is stable.
  101. for i in itr:
  102. j = Pack(UnReadSTR(i))
  103. if filter(checksubchan, j):
  104. yield i
  105. def findcodes(buf):
  106. ret = []
  107. i = 0
  108. l = len(buf)
  109. while i < l:
  110. j = buf.find('\x00\x00\x01', i)
  111. if j == -1 or (i + 4) >= l:
  112. break
  113. ret.append((j, buf[j + 3]))
  114. i = j + 4
  115. return ret
  116. class UnRead(file):
  117. def __init__(self, *args, **kwargs):
  118. super(UnRead, self).__init__(*args, **kwargs)
  119. self._buf = []
  120. self._buftot = 0
  121. def unread(self, buf):
  122. self._buf.append(buf)
  123. self._buftot += len(buf)
  124. def peek(self, size):
  125. r = self.read(size)
  126. self.unread(r)
  127. return r
  128. def read(self, size = None):
  129. if size is None and self._buf:
  130. ret = self._buf.pop()
  131. self._buftot -= len(ret)
  132. elif size is None:
  133. ret = super(UnRead, self).read()
  134. else:
  135. ret = []
  136. while size and self._buftot:
  137. ret.append(self._buf[-1][:size])
  138. l = len(ret[-1])
  139. if size > l:
  140. assert len(self._buf[-1]) == l
  141. self._buf.pop()
  142. else:
  143. self._buf[-1] = self._buf[-1][size:]
  144. self._buftot -= l
  145. size -= l
  146. if size:
  147. ret.append(super(UnRead, self).read(size))
  148. ret = ''.join(ret)
  149. return ret
  150. def read_timestamp(buf):
  151. assert len(buf) == 5
  152. assert (ord(buf[0]) & 0x1) == 1
  153. assert (ord(buf[2]) & 0x1) == 1
  154. assert (ord(buf[4]) & 0x1) == 1
  155. return (long(ord(buf[0]) & 0xe) << 29) | (ord(buf[1]) << 21) | \
  156. ((ord(buf[2]) & 0xfe) << 14) | (ord(buf[3]) << 7) | \
  157. ((ord(buf[4]) & 0xfe) >> 1)
  158. def read_escr(buf):
  159. assert len(buf) == 6
  160. assert (ord(buf[0]) & 0x4) == 0x4 and (ord(buf[2]) & 0x4) == 0x4
  161. assert (ord(buf[4]) & 0x4) == 0x4 and (ord(buf[5]) & 0x1) == 0x1
  162. base = (long(ord(buf[0]) & 0x38) << 27) | ((ord(buf[0]) & 0x3) << 28) |\
  163. (ord(buf[1]) << 20) | ((ord(buf[2]) & 0xf8) << 15) | \
  164. ((ord(buf[2]) & 0x3) << 13) | (ord(buf[3]) << 5) | \
  165. ((ord(buf[4]) & 0xf8) >> 3)
  166. extension = ((ord(buf[4]) & 0x3) << 7) | (ord(buf[5]) >> 1)
  167. return (base, extension)
  168. class MPEGWriter:
  169. END_CODE = '\xb9'
  170. def __init__(self, f):
  171. self.f = f
  172. self.SCR = (0, 0)
  173. def write_header(self, header):
  174. self.f.write('\x00\x00\x01' + header)
  175. def close(self):
  176. self.write_header(self.END_CODE)
  177. def __del__(self):
  178. self.close()
  179. class PES:
  180. PROGRAM_STREAM_MAP_ID = 0xbc
  181. PRIVATE_1_ID = 0xbd
  182. PADDING_ID = 0xbe
  183. PRIVATE_2_ID = 0xbf
  184. IS_AUDIO_ID = lambda x: (x & 0xe0) == 0xc0
  185. IS_VIDEO_ID = lambda x: (x & 0xf0) == 0xe0
  186. ECM_ID = 0xf0
  187. EMM_ID = 0xf1
  188. DSMCC_ID = 0xf2
  189. H2221_TYPE_E_ID = 0xf8
  190. PROGRAM_STREAM_DIRECTORY_ID = 0xff
  191. def __init__(self, buf):
  192. # Pull out an IndexError first
  193. assert buf[0] == '\x00' and buf[:3] == '\x00\x00\x01'
  194. self.stream_id = ord(buf[3])
  195. self.length = (ord(buf[4]) << 8) | ord(buf[5])
  196. if self.length == 0:
  197. self.length = len(buf)
  198. else:
  199. self.length += 6
  200. if len(buf) < self.length:
  201. raise IndexError, 'not enough data'
  202. if self.stream_id == self.PADDING_ID:
  203. # Validate padding?
  204. #self.length -= 6
  205. pass
  206. elif self.stream_id in (self.PROGRAM_STREAM_MAP_ID,
  207. self.PRIVATE_2_ID, self.ECM_ID, self.EMM_ID, self.DSMCC_ID,
  208. self.H2221_TYPE_E_ID, self.PROGRAM_STREAM_DIRECTORY_ID, ):
  209. self.data = buf[6:self.length]
  210. else:
  211. i = 6
  212. assert (ord(buf[i]) & 0xc0) == 0x80
  213. self.scrambling_control = (ord(buf[i]) & 0x30) >> 4
  214. self.priority = bool(ord(buf[i]) & 0x8)
  215. self.data_alignment = bool(ord(buf[i]) & 0x4)
  216. self.copyright = bool(ord(buf[i]) & 0x2)
  217. self.originalcopy = bool(ord(buf[i]) & 0x1)
  218. i +=1
  219. ptsdts_flag = (ord(buf[i]) & 0xc0) >> 6
  220. escr_flag = bool(ord(buf[i]) & 0x20)
  221. es_rate_flag = bool(ord(buf[i]) & 0x10)
  222. dsm_trick_mode_flag = bool(ord(buf[i]) & 0x8)
  223. additional_copy_info_flag = bool(ord(buf[i]) & 0x4)
  224. crc_flag = bool(ord(buf[i]) & 0x2)
  225. extension_flag = bool(ord(buf[i]) & 0x1)
  226. header_end = i + 2 + ord(buf[i + 1])
  227. i += 2
  228. if ptsdts_flag == 0x2:
  229. assert (ord(buf[i]) & 0xf0) == 0x20
  230. self.PTS = read_timestamp(buf[i:i + 5])
  231. i += 5
  232. elif ptsdts_flag == 0x3:
  233. assert (ord(buf[i]) & 0xf0) == 0x30
  234. self.PTS = read_timestamp(buf[i:i + 5])
  235. i += 5
  236. assert (ord(buf[i]) & 0xf0) == 0x10
  237. self.DTS = read_timestamp(buf[i:i + 5])
  238. i += 5
  239. elif ptsdts_flag == 0x1:
  240. raise ValueError, \
  241. "ptsdts flag forbidden: %d" % ptsdts_flag
  242. if escr_flag:
  243. self.ESCR = read_escr(buf[i:i + 6])
  244. i += 6
  245. if es_rate_flag:
  246. assert (ord(buf[i]) & 0x80) == 0x80
  247. assert (ord(buf[i + 2]) & 0x01) == 0x01
  248. self.ES_rate = ((ord(buf[i]) & 0x7f) << 15) | \
  249. (ord(buf[i + 1]) << 7) | \
  250. (ord(buf[i + 2]) >> 1)
  251. i += 3
  252. if dsm_trick_mode_flag:
  253. self.trick_mode_control = ord(buf[i]) >> 5
  254. self.trick_mode_bits = ord(buf[i]) & 0x1f
  255. i += 1
  256. if additional_copy_info_flag:
  257. assert (ord(buf[i]) & 0x80) == 0x80
  258. self.additional_copy_info = ord(buf[i]) & 0x7f
  259. i += 1
  260. if crc_flag:
  261. self.prev_crc = (ord(buf[i]) << 8) | \
  262. ord(buf[i + 1])
  263. i += 2
  264. if extension_flag:
  265. private_data_flag = bool(ord(buf[i]) & 0x80)
  266. pack_header_field_flag = bool(ord(buf[i]) & \
  267. 0x40)
  268. program_packet_sequence_counter_flag = \
  269. bool(ord(buf[i]) & 0x20)
  270. pstd_buffer_flag = bool(ord(buf[i]) & 0x10)
  271. pes_extension_flag_2 = bool(ord(buf[i]) & 0x01)
  272. i += 1
  273. if private_data_flag:
  274. self.private_data = buf[i:i + 16]
  275. i += 16
  276. if pack_header_field_flag:
  277. pack_field_length = ord(buf[i])
  278. self.pack_header = buf[i + 1:i + 1 +
  279. pack_field_length]
  280. i += 1 + pack_field_length
  281. if program_packet_sequence_counter_flag:
  282. assert (ord(buf[i]) & 0x80) == 0x80
  283. self.sequence_counter = \
  284. ord(buf[i]) & 0x7f
  285. i += 1
  286. assert (ord(buf[i]) & 0x80) == 0x80
  287. self.mpeg1_mpeg2_ident = \
  288. bool(ord(buf[i]) & 0x4)
  289. self.original_stuff_len = \
  290. ord(buf[i]) & 0x3f
  291. i += 1
  292. if pstd_buffer_flag:
  293. assert (ord(buf[i]) & 0xc0) == 0x40
  294. self.pstd_buffer_scale = \
  295. bool(ord(buf[i]) & 0x20)
  296. self.pstd_buffer_size = \
  297. ((ord(buf[i]) & 0x1f) << 8) | \
  298. ord(buf[i + 1])
  299. i += 2
  300. if pes_extension_flag_2:
  301. assert (ord(buf[i]) & 0x80) == 0x80
  302. extension_field_length = \
  303. ord(buf[i]) & 0x7f
  304. self.extension_field = buf[i + 1:i + \
  305. 1 + extension_field_length]
  306. i += 1 + extension_field_length
  307. assert i <= header_end
  308. self.data = buf[header_end:self.length]
  309. def __repr__(self):
  310. # XXX - data length
  311. v = ( 'length', 'scrambling_control',
  312. 'priority', 'data_alignment', 'copyright',
  313. 'originalcopy', 'PTS', 'DTS', 'ESCR', 'ES_rate',
  314. 'trick_mode_control', 'trick_mode_bits',
  315. 'additional_copy_info', 'pack_header',
  316. 'sequence_counter', 'mpeg1_mpeg2_ident',
  317. 'original_stuff_len', 'pstd_buffer_scale',
  318. 'pstd_buffer_size', 'extension_field', )
  319. return '<PES: stream_id: %#x, %s>' % (self.stream_id,
  320. ', '.join(attribreprlist(self, v)), )
  321. class Pack(list):
  322. def __init__(self, f = None, **keyw):
  323. super(Pack, self).__init__()
  324. if f is not None:
  325. d = f.read(14)
  326. assert d[:4] == '\x00\x00\x01\xba'
  327. assert (ord(d[4]) & 0xc0) == 0x40
  328. self.SCR = read_escr(d[4:10])
  329. assert ord(d[12]) & 0x3 == 0x3
  330. m = map(ord, d[10:13])
  331. self.muxr = (m[0] << 14) | (m[1] << 6) | (m[2] >> 2)
  332. self.stuff_len = ord(d[13]) & 0x7
  333. f.read(self.stuff_len)
  334. # system header
  335. d = f.peek(6)
  336. if d[:4] == '\x00\x00\x01\xbb':
  337. f.read(6)
  338. hlen = (ord(d[4]) << 8) | ord(d[5])
  339. header = f.read(hlen)
  340. oh = map(ord, header)
  341. assert (oh[0] & 0x80) == 0x80 and \
  342. (oh[2] & 0x1) == 0x1
  343. self.rate_bound = ((oh[0] & 0x7f) << 15) | \
  344. (oh[1] << 7) | (oh[2] >> 1)
  345. self.audio_bound = oh[3] >> 2
  346. self.fixed = bool(oh[3] & 0x2)
  347. self.CSPS = bool(oh[3] & 0x1)
  348. self.system_audio_lock = bool(oh[4] & 0x80)
  349. self.system_video_lock = bool(oh[4] & 0x40)
  350. assert (oh[4] & 0x20) == 0x20
  351. self.video_bound = oh[4] & 0x1f
  352. self.packet_rate_restriction = \
  353. bool(oh[5] & 0x80)
  354. d = f.peek(1)
  355. self.streams = {}
  356. while ord(d) & 0x80:
  357. d = map(ord, f.read(3))
  358. assert (d[1] & 0xc0) == 0xc0
  359. scaleflag = bool(d[1] & 0x20)
  360. self.streams[d[0]] = (((d[1] & 0x1f) <<
  361. 8) | d[2]) * (128, 1024)[scaleflag]
  362. d = f.peek(1)
  363. # PES packets
  364. d = f.peek(3)
  365. bytestoread = 2048
  366. while (f or d) and d == '\x00\x00\x01':
  367. try:
  368. d = f.read(bytestoread)
  369. self.append(PES(d))
  370. f.unread(d[self[-1].length:])
  371. except IndexError:
  372. f.unread(d)
  373. bytestoread <<= 2
  374. d = f.peek(4)
  375. else:
  376. self.SCR = keyw['SCR']
  377. self.muxr = keyw['muxr'] # in bps (converts to 50 bytes/sec)
  378. self.stuff_len = 0
  379. def __repr__(self):
  380. v = [ 'SCR', 'muxr', 'stuff_len',
  381. 'rate_bound', 'audio_bound', 'fixed', 'CSPS',
  382. 'system_audio_lock', 'system_video_lock',
  383. 'video_bound', 'packet_rate_restriction',
  384. 'streams',
  385. ]
  386. return '<Pack: %s %s>' % (', '.join(attribreprlist(self, v)),
  387. list.__repr__(self))
  388. def __str__(self):
  389. buf = []
  390. buf.append('\x00\x00\x01\xba')
  391. clock = (1l << 46) | (((self.SCR[0] >> 30) & 0x7) << 43) | \
  392. (1l << 42) | (((self.SCR[0] >> 15) & 0x7ffff) << 27) | \
  393. (1 << 26) | ((self.SCR[0] & 0x7fff) << 11) | (1 << 10) | \
  394. ((self.SCR[1] << 1) & 0x3fe) | 0x1
  395. for i in range(6):
  396. buf.append(chr(clock >> ((5 - i) * 8) & 0xff))
  397. muxr = self.muxr / 50 / 8
  398. buf.append(chr((muxr >> 14) & 0xff))
  399. buf.append(chr((muxr >> 6) & 0xff))
  400. buf.append(chr(((muxr << 2) & 0xfc) | 0x3))
  401. buf.append(chr(0xf8 | (self.stuff_len & 7)))
  402. buf.append('\xff' * self.stuff_len)
  403. buf.extend(map(str, self))
  404. return ''.join(buf)
  405. # These are strings due to the floating point numbers
  406. frame_rate_code = {
  407. 0x0: 'forbidden', 0x1: '23.976', 0x2: '24', 0x3: '25',
  408. 0x4: '29.97', 0x5: '30', 0x6: '50', 0x7: '59.95',
  409. 0x8: '60', 0x9: 'reserved', 0xa: 'reserved',
  410. 0xb: 'reserved', 0xc: 'reserved', 0xd: 'reserved',
  411. 0xe: 'reserved', 0xf: 'reserved',
  412. }
  413. chroma_format = {
  414. 0x0: 'reserved', 0x1: '4:2:0', 0x2: '4:2:2', 0x3: '4:4:4',
  415. }
  416. class BitRate(int):
  417. def __init__(self, bitrate):
  418. super(BitRate, self).__init__(bitrate)
  419. def __str__(self):
  420. return repr(self)
  421. def __repr__(self):
  422. return '%dbps' % self
  423. def max_bitrate_descriptor(b):
  424. assert len(b) == 3
  425. return BitRate((((ord(b[0]) & 0x3f) << 16) |
  426. ((ord(b[1]) & 0xff) << 8) | (ord(b[0]) & 0xff)) * 50 * 8)
  427. class ISO639LangDescriptor(list):
  428. atypedict = {
  429. 0: 'undefined',
  430. 1: 'clean effects',
  431. 2: 'hearing impaired',
  432. 3: 'visual impaired commentary',
  433. }
  434. def __init__(self, b):
  435. assert len(b) % 4 == 0
  436. for i in range(len(b) / 4):
  437. lang = unicode(b[i * 4:i * 4 + 3], 'iso8859-1')
  438. atype = self.atypedict[ord(b[i * 4 + 3])]
  439. self.append((lang, atype))
  440. class VStreamDescriptor:
  441. def __init__(self, b):
  442. if not b:
  443. self.mpeg2 = None
  444. self.multiple_frame_rate = None
  445. self.frame_rate_code = None
  446. self.constrained_parameter = None
  447. self.still_picture = None
  448. return
  449. fb = ord(b[0])
  450. # XXX - libdvbpsi says no not for mpeg2 flag, but my data
  451. # seems to say otherwise.
  452. self.mpeg2 = not bool(fb & 0x04)
  453. assert (not self.mpeg2 and len(b) == 1) or (self.mpeg2 and
  454. len(b) == 3)
  455. self.multiple_frame_rate = bool(fb & 0x80)
  456. self.frame_rate_code = frame_rate_code[(fb & 0x78) >> 3]
  457. self.constrained_parameter = bool(fb & 0x02)
  458. self.still_picture = bool(fb & 0x01)
  459. if self.mpeg2:
  460. self.profile_level_indication = ord(b[1])
  461. tb = ord(b[2])
  462. self.chroma_format = chroma_format[(tb & 0xc0) >> 6]
  463. self.frame_rate_extension = bool(tb & 0x20)
  464. def __repr__(self):
  465. v = ['mpeg2', 'multiple_frame_rate', 'frame_rate_code',
  466. 'constrained_parameter', 'still_picture',
  467. 'profile_level_indication', 'chroma_format',
  468. 'frame_rate_extension', ]
  469. return '<VStream: %s>' % (', '.join(attribreprlist(self, v)), )
  470. class AC3Descriptor:
  471. src_dict = { 0: '48k', 1: '44.1k', 2: '32k', 3: None, 4: '48k or 44.1k',
  472. 5: '48k or 32k', 6: '44.1k or 32k', 7: '48k or 44.1k or 32k' }
  473. brc_dict = { 0: 32, 1: 40, 2: 48, 3: 56, 4: 64, 5: 80, 6: 96, 7: 112,
  474. 8: 128, 9: 160, 10: 192, 11: 224, 12: 256, 13: 320, 14: 384,
  475. 15: 448, 16: 512, 17: 576, 18: 640, }
  476. sm_dict = { 0: 'Not indicated', 1: 'NOT Dolby surround encoded',
  477. 2: 'Dolby surround encoded', 3: 'Reserved', }
  478. bsmod_dict = { 0: 'main: complete', 1: 'main: music and effects',
  479. 2: 'associated: visually imparied',
  480. 3: 'associated: hearing imparied', 4: 'associated: dialogue',
  481. 5: 'associated: commentary', 6: 'associated: emergency', }
  482. bs_mod = property(lambda x: x.bsmoddesc())
  483. num_channels = property(lambda x: x.numchan_dict[x.numchan])
  484. def bsmoddesc(self):
  485. if self.bsmod == 7:
  486. if (self.numchan & 0x8) and self.numchan == 1:
  487. return 'associated: voice over'
  488. else:
  489. return 'main: karaoke'
  490. else:
  491. return self.bsmod_dict[self.bsmod]
  492. numchan_dict = { 0: '1+1', 1: '1/0', 2: '2/0', 3: '3/0', 4: '2/1',
  493. 5: '3/1', 6: '2/2', 7: '3/2', 8: '1', 9: '<=2', 10: '<=3',
  494. 11: '<=4', 12: '<=5', 13: '<=6', 14: 'Reserved',
  495. 15: 'Reserved', }
  496. def __init__(self, data):
  497. srcbsid = ord(data[0])
  498. self.sample_rate = self.src_dict[srcbsid >> 5]
  499. self.bsid = srcbsid & 0x1f
  500. brcsm = ord(data[1])
  501. self.br_exact = (brcsm & 0x80) == 0x80
  502. self.bitrate = self.brc_dict[(brcsm >> 2) & 0x1f]
  503. self.surround_mode = self.sm_dict[brcsm & 0x3]
  504. bsmodnumchanfullsvc = ord(data[2])
  505. self.bsmod = bsmodnumchanfullsvc >> 6
  506. numchan = (bsmodnumchanfullsvc >> 1) & 0xf
  507. self.numchan = numchan
  508. # KTVU only puts 3 bytes here
  509. if len(data) == 3:
  510. return
  511. i = 4
  512. # dropped langcod as not used per A/52a 3.4
  513. if numchan == 0:
  514. i += 1
  515. if self.bsmod < 2:
  516. self.mainid = ord(data[i]) >> 5
  517. else:
  518. self.asvcflags = ord(data[i])
  519. i += 1
  520. if i >= len(data):
  521. self.text = ''
  522. return
  523. textlangcode = ord(data[i])
  524. textlen = textlangcode >> 1
  525. i += 1
  526. txt = data[i:i + textlen]
  527. if textlangcode & 1:
  528. self.text = txt.decode('latin-1')
  529. else:
  530. assert NotImplementedError, \
  531. 'the following code is untested'
  532. self.text = ''.join(map(lambda x:
  533. unichr(ord(x[0]) * 256 + ord(x[1])),
  534. [txt[i:i+2] for i in range(0, len(txt), 2)]))
  535. def __repr__(self):
  536. v = ['sample_rate', 'bsid', 'br_exact', 'bitrate',
  537. 'surround_mode', 'bs_mod', 'num_channels', 'mainid',
  538. 'asvcflags', 'text', ]
  539. return '<AC3Descritor: %s>' % (', '.join(attribreprlist(self,
  540. v)), )
  541. class ContentAdvisory(list):
  542. def __init__(self, data):
  543. list.__init__(self)
  544. cnt = ord(data[0]) & 0x3f
  545. i = 1
  546. for j in xrange(cnt):
  547. region, dim = struct.unpack('>BB', data[i: i + 2])
  548. i += 2
  549. d = {}
  550. for j in xrange(dim):
  551. d[ord(data[i])] = ord(data[i + 1]) & 0xf
  552. i += 2
  553. desclen = ord(data[i])
  554. desc = MultiStringStruct(data[i + 1: i + 1 + desclen])
  555. self.append((region, d, desc))
  556. def __repr__(self):
  557. return '<ContentAdvisory: %s>' % list.__repr__(self)
  558. class ServiceLocationDescriptor(list):
  559. tag = 0xa1
  560. sldel = '>BH3c'
  561. def __init__(self, data):
  562. step = struct.calcsize(self.sldel)
  563. assert ((len(data) - 3) % step) == 0
  564. list.__init__(self)
  565. self.pcr_pid, cnt = struct.unpack('>HB', data[:3])
  566. self.pcr_pid &= 0x1fff
  567. for i in range(cnt):
  568. type, pid, a, b, c = struct.unpack(self.sldel,
  569. data[3 + i * step:3 + (i + 1) * step])
  570. pid &= 0x1fff
  571. lang = a + b + c
  572. if lang == '\x00' * 3:
  573. lang = None
  574. self.append({ 'type': type, 'pid': pid, 'lang': lang })
  575. def __repr__(self):
  576. return '<ServiceLocationDescriptor: pcr_pid: %d, %s>' % \
  577. (self.pcr_pid, list.__repr__(self))
  578. class MultiStringStruct(dict):
  579. '''Conforms to Section 6.10 of A/65b.'''
  580. def decode(self, comp, mode, data):
  581. assert (mode == 0 and comp in (1, 2)) or comp == 0, \
  582. 'mode: %#x, comp: %#x' % (mode, comp)
  583. if comp == 0:
  584. if mode == 0x3f:
  585. return data.decode('UTF-16-BE')
  586. elif mode == 0x3e:
  587. # http://www.unicode.org/reports/tr6/
  588. raise NotImplementedError, 'Unicode Technical Report #6, A Standard Compression Scheme for Unicode'
  589. # There are additional limitations
  590. assert mode < 0x34, 'Invalid mode: %#x' % mode
  591. return ''.join(map(lambda x, y = mode * 256:
  592. unichr(ord(x) + y), data))
  593. assert (comp == 1 or comp == 2) and mode == 0xff, \
  594. 'Invalid comp: %#x, mode: %#x' % (comp, mode)
  595. if comp == 1:
  596. return atschuff.decode_title(data)
  597. else:
  598. return atschuff.decode_description(data)
  599. def __init__(self, data):
  600. cnt = ord(data[0])
  601. off = 1
  602. for i in range(cnt):
  603. lang = data[off:off + 3]
  604. nseg = ord(data[off + 3])
  605. segs = []
  606. self[lang] = segs
  607. off += 4
  608. for j in range(nseg):
  609. comp_type = ord(data[off])
  610. mode = ord(data[off + 1])
  611. nbytes = ord(data[off + 2])
  612. segs.append(self.decode(comp_type, mode,
  613. data[off + 3: off + 3 + nbytes]))
  614. class ComponentNameDescriptor(MultiStringStruct):
  615. def __repr__(self):
  616. return '<ComponentNameDescriptor: %s>' % \
  617. MultiStringStruct.__repr__(self)
  618. def FindMe(data):
  619. raise RuntimeError, 'found me'
  620. Descriptors = {
  621. # 0-63 Are listed in ISO 13818-1 Table 2-40
  622. 2: VStreamDescriptor, # ISO 13818-1 Section 2.6.2
  623. # 3: Audio, # ISO 13818-1 Section 2.6.3
  624. 10: ISO639LangDescriptor, # ISO 13818-1 Section 2.6.18
  625. 14: max_bitrate_descriptor, # ISO 13818-1 Section 2.6.26
  626. 0x81: AC3Descriptor, # A/53d Section 5.7.3.1
  627. 0x87: ContentAdvisory, # A/65b Section 6.9.4
  628. # 0xa0: ExtendedChannelName, # A/65b Section 6.9.5
  629. 0xa1: ServiceLocationDescriptor, # A/65b Section 6.9.6
  630. # 0xa2: TimeShiftedService, # A/65b Section 6.9.7
  631. 0xa3: ComponentNameDescriptor, # A/65b Section 6.9.8
  632. # 0xad: undefined, # A/53d Section 5.7.3.4
  633. 0xb6: FindMe, # A/57a Section 7 (ContentId)
  634. }
  635. PIDs = {
  636. 0x00: ('PAT', 'Program Association Table'),
  637. 0x01: ('CAT', 'Conditional Access Table'),
  638. 0x02: ('TSDT', 'Program Stream Descriptor Table'),
  639. 0x10: ('NIT', 'Network Information Table'),
  640. 0x11: ('BAT', 'Bouquet Association Table'),
  641. 0x11: ('SDT', 'Service Descriptor Table'),
  642. 0x12: ('EIT', 'Event Information Table'),
  643. 0x13: ('RST', 'running Status Table'),
  644. 0x14: ('TOT', 'Time Offset Table'),
  645. }
  646. def psip_calc_crc32(data, verbose = False, table = (
  647. 0x00000000l, 0x04c11db7l, 0x09823b6el, 0x0d4326d9l,
  648. 0x130476dcl, 0x17c56b6bl, 0x1a864db2l, 0x1e475005l,
  649. 0x2608edb8l, 0x22c9f00fl, 0x2f8ad6d6l, 0x2b4bcb61l,
  650. 0x350c9b64l, 0x31cd86d3l, 0x3c8ea00al, 0x384fbdbdl,
  651. 0x4c11db70l, 0x48d0c6c7l, 0x4593e01el, 0x4152fda9l,
  652. 0x5f15adacl, 0x5bd4b01bl, 0x569796c2l, 0x52568b75l,
  653. 0x6a1936c8l, 0x6ed82b7fl, 0x639b0da6l, 0x675a1011l,
  654. 0x791d4014l, 0x7ddc5da3l, 0x709f7b7al, 0x745e66cdl,
  655. 0x9823b6e0l, 0x9ce2ab57l, 0x91a18d8el, 0x95609039l,
  656. 0x8b27c03cl, 0x8fe6dd8bl, 0x82a5fb52l, 0x8664e6e5l,
  657. 0xbe2b5b58l, 0xbaea46efl, 0xb7a96036l, 0xb3687d81l,
  658. 0xad2f2d84l, 0xa9ee3033l, 0xa4ad16eal, 0xa06c0b5dl,
  659. 0xd4326d90l, 0xd0f37027l, 0xddb056fel, 0xd9714b49l,
  660. 0xc7361b4cl, 0xc3f706fbl, 0xceb42022l, 0xca753d95l,
  661. 0xf23a8028l, 0xf6fb9d9fl, 0xfbb8bb46l, 0xff79a6f1l,
  662. 0xe13ef6f4l, 0xe5ffeb43l, 0xe8bccd9al, 0xec7dd02dl,
  663. 0x34867077l, 0x30476dc0l, 0x3d044b19l, 0x39c556ael,
  664. 0x278206abl, 0x23431b1cl, 0x2e003dc5l, 0x2ac12072l,
  665. 0x128e9dcfl, 0x164f8078l, 0x1b0ca6a1l, 0x1fcdbb16l,
  666. 0x018aeb13l, 0x054bf6a4l, 0x0808d07dl, 0x0cc9cdcal,
  667. 0x7897ab07l, 0x7c56b6b0l, 0x71159069l, 0x75d48ddel,
  668. 0x6b93dddbl, 0x6f52c06cl, 0x6211e6b5l, 0x66d0fb02l,
  669. 0x5e9f46bfl, 0x5a5e5b08l, 0x571d7dd1l, 0x53dc6066l,
  670. 0x4d9b3063l, 0x495a2dd4l, 0x44190b0dl, 0x40d816bal,
  671. 0xaca5c697l, 0xa864db20l, 0xa527fdf9l, 0xa1e6e04el,
  672. 0xbfa1b04bl, 0xbb60adfcl, 0xb6238b25l, 0xb2e29692l,
  673. 0x8aad2b2fl, 0x8e6c3698l, 0x832f1041l, 0x87ee0df6l,
  674. 0x99a95df3l, 0x9d684044l, 0x902b669dl, 0x94ea7b2al,
  675. 0xe0b41de7l, 0xe4750050l, 0xe9362689l, 0xedf73b3el,
  676. 0xf3b06b3bl, 0xf771768cl, 0xfa325055l, 0xfef34de2l,
  677. 0xc6bcf05fl, 0xc27dede8l, 0xcf3ecb31l, 0xcbffd686l,
  678. 0xd5b88683l, 0xd1799b34l, 0xdc3abdedl, 0xd8fba05al,
  679. 0x690ce0eel, 0x6dcdfd59l, 0x608edb80l, 0x644fc637l,
  680. 0x7a089632l, 0x7ec98b85l, 0x738aad5cl, 0x774bb0ebl,
  681. 0x4f040d56l, 0x4bc510e1l, 0x46863638l, 0x42472b8fl,
  682. 0x5c007b8al, 0x58c1663dl, 0x558240e4l, 0x51435d53l,
  683. 0x251d3b9el, 0x21dc2629l, 0x2c9f00f0l, 0x285e1d47l,
  684. 0x36194d42l, 0x32d850f5l, 0x3f9b762cl, 0x3b5a6b9bl,
  685. 0x0315d626l, 0x07d4cb91l, 0x0a97ed48l, 0x0e56f0ffl,
  686. 0x1011a0fal, 0x14d0bd4dl, 0x19939b94l, 0x1d528623l,
  687. 0xf12f560el, 0xf5ee4bb9l, 0xf8ad6d60l, 0xfc6c70d7l,
  688. 0xe22b20d2l, 0xe6ea3d65l, 0xeba91bbcl, 0xef68060bl,
  689. 0xd727bbb6l, 0xd3e6a601l, 0xdea580d8l, 0xda649d6fl,
  690. 0xc423cd6al, 0xc0e2d0ddl, 0xcda1f604l, 0xc960ebb3l,
  691. 0xbd3e8d7el, 0xb9ff90c9l, 0xb4bcb610l, 0xb07daba7l,
  692. 0xae3afba2l, 0xaafbe615l, 0xa7b8c0ccl, 0xa379dd7bl,
  693. 0x9b3660c6l, 0x9ff77d71l, 0x92b45ba8l, 0x9675461fl,
  694. 0x8832161al, 0x8cf30badl, 0x81b02d74l, 0x857130c3l,
  695. 0x5d8a9099l, 0x594b8d2el, 0x5408abf7l, 0x50c9b640l,
  696. 0x4e8ee645l, 0x4a4ffbf2l, 0x470cdd2bl, 0x43cdc09cl,
  697. 0x7b827d21l, 0x7f436096l, 0x7200464fl, 0x76c15bf8l,
  698. 0x68860bfdl, 0x6c47164al, 0x61043093l, 0x65c52d24l,
  699. 0x119b4be9l, 0x155a565el, 0x18197087l, 0x1cd86d30l,
  700. 0x029f3d35l, 0x065e2082l, 0x0b1d065bl, 0x0fdc1becl,
  701. 0x3793a651l, 0x3352bbe6l, 0x3e119d3fl, 0x3ad08088l,
  702. 0x2497d08dl, 0x2056cd3al, 0x2d15ebe3l, 0x29d4f654l,
  703. 0xc5a92679l, 0xc1683bcel, 0xcc2b1d17l, 0xc8ea00a0l,
  704. 0xd6ad50a5l, 0xd26c4d12l, 0xdf2f6bcbl, 0xdbee767cl,
  705. 0xe3a1cbc1l, 0xe760d676l, 0xea23f0afl, 0xeee2ed18l,
  706. 0xf0a5bd1dl, 0xf464a0aal, 0xf9278673l, 0xfde69bc4l,
  707. 0x89b8fd09l, 0x8d79e0bel, 0x803ac667l, 0x84fbdbd0l,
  708. 0x9abc8bd5l, 0x9e7d9662l, 0x933eb0bbl, 0x97ffad0cl,
  709. 0xafb010b1l, 0xab710d06l, 0xa6322bdfl, 0xa2f33668l,
  710. 0xbcb4666dl, 0xb8757bdal, 0xb5365d03l, 0xb1f740b4l
  711. )):
  712. '''Validate a PSIP CRC. Include the CRC in the data. The return value will be the valid data, or an exception will be raised if invalid.'''
  713. if verbose:
  714. i_crc = 0xffffffffl
  715. for i in data:
  716. i_crc = ((i_crc << 8) & 0xffffffffl) ^ table[(i_crc >>
  717. 24) ^ ord(i)]
  718. print hex(i_crc)
  719. else:
  720. i_crc = reduce(lambda x, y: ((x << 8) & 0xffffffffl) ^
  721. table[(x >> 24) ^ ord(y)], data, 0xffffffffl)
  722. return i_crc
  723. def psip_crc32(data):
  724. return psip_calc_crc32(data) == 0
  725. def getdescriptors(tb):
  726. d = {}
  727. i = 0
  728. while i < len(tb):
  729. t = ord(tb[i])
  730. if d.has_key(t):
  731. l = ord(tb[i + 1])
  732. data = tb[i + 2: i + 2 + l]
  733. #print repr(d[t]), t, repr(data)
  734. #assert not d.has_key(t)
  735. l = ord(tb[i + 1])
  736. data = tb[i + 2: i + 2 + l]
  737. try:
  738. item = Descriptors[t](data)
  739. except KeyError:
  740. item = data
  741. try:
  742. d[t].append(item)
  743. except KeyError:
  744. d[t] = [ item ]
  745. i += 2 + l
  746. return d
  747. class TSPSIPHandler(dict):
  748. '''This object is used to represent the tables that come in on a
  749. specific PID. Since there can be multiple tables on a specific PID
  750. (ATSC's 0x1ffb), a dictionary of callable objects must be passed in,
  751. and the key is the table number.'''
  752. def __init__(self, *t):
  753. super(TSPSIPHandler, self).__init__()
  754. self.update(*t)
  755. self.discontinuity = True
  756. self.complete = False
  757. self.last_continuity = None
  758. # config knobs
  759. self.current_only = True
  760. self.ignerror = False
  761. def next_continuity(self, nc):
  762. if self.last_continuity is None:
  763. return True
  764. return ((self.last_continuity + 1) % 16) != nc
  765. def get_table_id(self):
  766. if self.complete:
  767. return self._table_id
  768. return None
  769. table_id = property(get_table_id)
  770. def decode_section_header(self, payload, i):
  771. self._table_id = ord(payload[i])
  772. self.syntax = bool(ord(payload[i + 1]) & 0x80)
  773. self.private = bool(ord(payload[i + 1]) & 0x40)
  774. self.sect_len = (((ord(payload[i + 1]) & 0xf) << 8) | \
  775. ord(payload[i + 2])) + 3
  776. self.stored_sects = [ payload[i:] ]
  777. #print 'bar', i, repr(payload)
  778. self.stored_len = len(self.stored_sects[0])
  779. self.discontinuity = False
  780. def __call__(self, p):
  781. '''Pass in a TSPacket instance.'''
  782. if p.error and not self.ignerror:
  783. return
  784. if p.start:
  785. payload = p.payload
  786. i = ord(payload[0]) + 1
  787. self.decode_section_header(payload, i)
  788. else:
  789. if self.discontinuity or \
  790. self.next_continuity(p.continuity):
  791. self.discontinuity = True
  792. return
  793. self.stored_sects.append(p.payload)
  794. self.stored_len += len(p.payload)
  795. while self.table_id != 0xff:
  796. if self.stored_len < self.sect_len:
  797. # we need more data
  798. self.last_continuity = p.continuity
  799. return
  800. payload = ''.join(self.stored_sects)
  801. assert len(payload) == self.stored_len
  802. if self.syntax:
  803. # XXX I may need to include the skipped part
  804. # above in the crc calculations.
  805. if not psip_crc32(payload[:self.sect_len]):
  806. raise ValueError, \
  807. 'CRC check failed: %s' % \
  808. `payload[:self.sect_len]`
  809. self.extension = (ord(payload[3]) << 8) | \
  810. ord(payload[4])
  811. self.version = (ord(payload[5]) & 0x3e) >> 1
  812. self.current_next = bool(ord(payload[5]) & 1)
  813. self.section_number = ord(payload[6])
  814. self.last_section_number = ord(payload[7])
  815. self.protocol_version = ord(payload[8])
  816. # don't include the CRC
  817. self.table = payload[8:self.sect_len - 4]
  818. #if self.last_section_number:
  819. # print repr(self), repr(p)
  820. else:
  821. self.table = payload[3:self.sect_len]
  822. self.complete = True
  823. if self.current_only and not self.current_next:
  824. continue
  825. # If this fails there are multiple sections
  826. try:
  827. self[self.table_id].clean_up()
  828. self[self.table_id](self)
  829. except KeyError:
  830. pass # No handler, ignore or raise exception?
  831. # hmm. I had a packet with some low bits clear
  832. # the spec seems to imply that there can be multiple
  833. # sections, but every case I've seen in the world
  834. # there isn't.
  835. if ord(payload[self.sect_len]) != 0xff:
  836. #print 'prev:', self.last_section_number
  837. # I should make sure there is enough data
  838. self.decode_section_header(payload,
  839. self.sect_len)
  840. #print 'starting next section:', repr(self), repr(payload)
  841. continue
  842. else:
  843. break
  844. def __repr__(self, v=('table_id', 'syntax', 'private', 'table',
  845. 'extension', 'version', 'current_next', 'section_number',
  846. 'last_section_number', 'protocol_version', )):
  847. return '<TSPSIPHandler: %s, table objects: %s>' % \
  848. (', '.join(attribreprlist(self, v)), super(TSPSIPHandler,
  849. self).__repr__())
  850. class PSIPObject(object):
  851. def parse_table(self, tbl):
  852. raise NotImplementedError
  853. def repr_part(self):
  854. return []
  855. def __call__(self, psip):
  856. if psip.syntax:
  857. self.version = psip.version
  858. self.current_next = psip.current_next
  859. self.section_number = psip.section_number
  860. self.last_section_number = psip.last_section_number
  861. else:
  862. self.version = None
  863. self.current_next = None
  864. self.section_number = None
  865. self.last_section_number = None
  866. self.parse_table(psip)
  867. def __repr__(self, v=('version', 'current_next', 'section_number',
  868. 'last_section_number', )):
  869. return '<%s: %s>' % (self.__class__.__name__,
  870. ', '.join(attribreprlist(self, v) + self.repr_part()))
  871. class PAT(PSIPObject, dict):
  872. def __init__(self):
  873. '''In order to prevent confusion, you can't init w/ a packet.'''
  874. PSIPObject.__init__(self)
  875. dict.__init__(self)
  876. self.pid_dict = {}
  877. def clean_up(self):
  878. self.pid_dict = {}
  879. self.clear()
  880. def has_pid(self, pid):
  881. return self.pid_dict.has_key(pid)
  882. def get_prog(self, pid):
  883. return self.pid_dict[pid]
  884. def parse_table(self, psip, s = '>HH', sl = struct.calcsize('>HH')):
  885. assert psip.table_id == 0x00
  886. for i in range(len(psip.table) / sl):
  887. prog, pid = struct.unpack(s, psip.table[i * sl:(i +
  888. 1) * sl])
  889. pid &= 0x1fff
  890. self.pid_dict[pid] = prog
  891. self[prog] = pid
  892. def repr_part(self):
  893. return [ dict.__repr__(self) ]
  894. def getaudiovideopids(pmt, lang = None):
  895. anapid = None
  896. apids = []
  897. vpids = []
  898. for i in pmt.es:
  899. cpid = i[1]
  900. j = i[2]
  901. if i[0] == 2:
  902. vpids.append(cpid)
  903. elif i[0] == 129:
  904. apids.append(cpid)
  905. elif j.has_key(5) and i[0] != 5:
  906. assert 'AC-3' in map(lambda x: x[:4], j[5]), (i, j)
  907. if lang is None or lang == j[10][0][0]:
  908. apids.append(cpid)
  909. else:
  910. anapid = cpid
  911. if not apids and anapid is not None:
  912. apids.append(anapid)
  913. return (apids, vpids)
  914. def iteravpids(stream, avpids):
  915. avpids = sets.ImmutableSet(avpids)
  916. for i in stream:
  917. if SimpleTSPacket(i).pid in avpids:
  918. yield i
  919. class PMT(PSIPObject, dict):
  920. def __init__(self):
  921. PSIPObject.__init__(self)
  922. dict.__init__(self)
  923. self.pcrpid = None
  924. self.es = []
  925. def clean_up(self):
  926. self.clear()
  927. del self.es[:]
  928. def __nonzero__(self):
  929. return len(self) or bool(self.es)
  930. def parse_table(self, psip):
  931. assert psip.table_id == 0x02
  932. tb = psip.table
  933. pcrpid = ((ord(tb[0]) & 0x1f) << 8) | ord(tb[1])
  934. self.pcrpid = pcrpid
  935. ltmp = ((ord(tb[2]) & 0xf) << 8) | ord(tb[3]) + 4
  936. self.update(getdescriptors(tb[4:ltmp]))
  937. i = ltmp
  938. es = self.es
  939. while i < len(tb):
  940. t = ord(tb[i])
  941. p = ((ord(tb[i + 1]) & 0x1f) << 8) | ord(tb[i + 2])
  942. l = ((ord(tb[i + 3]) & 0x0f) << 8) | ord(tb[i + 4])
  943. i += 5
  944. d = getdescriptors(tb[i:i + l])
  945. i += l
  946. es.append((t, p, d))
  947. def repr_part(self):
  948. return [ 'PCRpid: %d' % self.pcrpid, dict.__repr__(self),
  949. 'ES: %s' % `self.es` ]
  950. def channelmajorminorsort(x, y):
  951. if x['major'] != y['major']:
  952. return cmp(x['major'], y['major'])
  953. return cmp(x['minor'], y['minor'])
  954. def gpstoutc(gps, utcoff):
  955. gpstrue = gps - utcoff
  956. return gpstrue + 315990000
  957. class STT(PSIPObject):
  958. def __init__(self):
  959. '''In order to prevent confusion, you can't init w/ a packet.'''
  960. PSIPObject.__init__(self)
  961. def clean_up(self):
  962. self.utc = None
  963. self.ds_status = None
  964. self.ds_day_of_month = None
  965. self.ds_hour = None
  966. def parse_table(self, psip):
  967. assert psip.table_id == 0xcd and psip.table[0] == '\x00'
  968. system_time, gps_utc_offset, daylight_savings = \
  969. struct.unpack('>IBH', psip.table[1:8])
  970. ds_status = daylight_savings >> 15
  971. ds_day_of_month = (daylight_savings >> 8) & 0x1f
  972. ds_hour = daylight_savings & 0xff
  973. utc = gpstoutc(system_time, gps_utc_offset)
  974. self.utc = utc
  975. self.ds_status = ds_status
  976. self.ds_day_of_month = ds_day_of_month
  977. self.ds_hour = ds_hour
  978. def repr_part(self, v=('ds_status', 'ds_day_of_month', 'ds_hour', )):
  979. return [ `time.ctime(self.utc)`, ] + attribreprlist(self, v)
  980. class MGT(list):
  981. def __init__(self, pidtable):
  982. '''In order to prevent confusion, you can't init w/ a packet.'''
  983. super(MGT, self).__init__()
  984. self.pidtable = pidtable
  985. self.watch = {}
  986. def clean_up(self):
  987. del self[:]
  988. def __call__(self, psip):
  989. assert psip.table_id == 0xc7 and psip.table[0] == '\x00'
  990. ntables = struct.unpack('>H', psip.table[1:3])[0]
  991. i = 3
  992. for foo in xrange(ntables):
  993. type, pid, version, nbytes, desclen = \
  994. struct.unpack('>HHBIH', psip.table[i:i + 11])
  995. i += 11
  996. pid &= 0x1fff
  997. version &= 0x1f
  998. desclen &= 0xfff
  999. desc = getdescriptors(psip.table[i:i + desclen])
  1000. self.append((type, pid, version, nbytes, desc))
  1001. i += desclen
  1002. # start watch
  1003. if type >= 0x100 and type <= 0x17f:
  1004. if self.pidtable.has_key(pid):
  1005. # XXX - check that it's in watch
  1006. pass
  1007. else:
  1008. self.watch[type] = { 'pid': pid,
  1009. 'version': version, }
  1010. self.pidtable[pid] = TSPSIPHandler({
  1011. 0xcb: EIT() })
  1012. elif type >= 0x200 and type <= 0x27f:
  1013. if self.pidtable.has_key(pid):
  1014. # XXX - check that it's in watch
  1015. pass
  1016. else:
  1017. #print 'adding ett', pid
  1018. self.watch[type] = { 'pid': pid,
  1019. 'version': version, }
  1020. self.pidtable[pid] = TSPSIPHandler({
  1021. 0xcc: ETT() })
  1022. desclen = struct.unpack('>H', psip.table[i:i + 2])[0]
  1023. desclen &= 0xfff
  1024. desc = getdescriptors(psip.table[i:i + desclen])
  1025. self.desc = desc
  1026. #print `self`
  1027. def __repr__(self):
  1028. return '<MGT: descriptors: %s, loop: %s>' % (`self.desc`,
  1029. list.__repr__(self))
  1030. class EIT(list):
  1031. def __init__(self):
  1032. '''In order to prevent confusion, you can't init w/ a packet.'''
  1033. super(EIT, self).__init__()
  1034. def clean_up(self):
  1035. del self[:]
  1036. def __call__(self, psip):
  1037. assert psip.table_id == 0xcb and psip.table[0] == '\x00'
  1038. ntables = ord(psip.table[1])
  1039. i = 2
  1040. for foo in xrange(ntables):
  1041. event_id, start_time, lochilen, lolength, titlelen = \
  1042. struct.unpack('>HIBHB', psip.table[i:i + 10])
  1043. i += 10
  1044. event_id &= 0x3fff
  1045. etm_location = (lochilen >> 4) & 0x3
  1046. length = ((lochilen & 0xf) << 16) | lolength
  1047. title = MultiStringStruct(psip.table[i:i + titlelen])
  1048. i += titlelen
  1049. desclen = struct.unpack('>H', psip.table[i:i + 2])[0]
  1050. i += 2
  1051. desclen &= 0xfff
  1052. desc = getdescriptors(psip.table[i:i + desclen])
  1053. i += desclen
  1054. # XXX - UTC offset should be what?
  1055. self.append((event_id, etm_location,
  1056. gpstoutc(start_time, 0), length, title, desc))
  1057. #print `self`
  1058. def __repr__(self):
  1059. return '<EIT: %s>' % list.__repr__(self)
  1060. class TVCT(PSIPObject, dict):
  1061. def __init__(self):
  1062. '''In order to prevent confusion, you can't init w/ a packet.'''
  1063. PSIPObject.__init__(self)
  1064. dict.__init__(self)
  1065. def clean_up(self):
  1066. self.clear()
  1067. def parse_table(self, psip):
  1068. assert psip.table_id == 0xc8
  1069. self['channels'] = []
  1070. tb = psip.table
  1071. i = ord(tb[0]) + 1
  1072. chancnt = ord(tb[i])
  1073. i += 1
  1074. for foo in range(chancnt):
  1075. shrtnm = ''.join(map(lambda x: unichr((ord(x[0]) <<
  1076. 8) | ord(x[1])), [tb[i + x * 2:i + (x + 1) * 2] for
  1077. x in range(7)])).rstrip(unichr(0))
  1078. i += 7 * 2
  1079. major = (((ord(tb[i]) << 8) | ord(tb[i + 1])) >> 2) & \
  1080. 0x3ff
  1081. minor = ((ord(tb[i + 1]) & 0x3) << 8) | ord(tb[i + 2])
  1082. mode = ord(tb[i + 3])
  1083. i += 4
  1084. carrier, tsid, prog_num, flagsa, source, desc_len = \
  1085. struct.unpack('>IHHHHH', tb[i:i + 14])
  1086. i += 14
  1087. etm_loc = (flagsa & 0xc000) >> 14
  1088. access_control = bool(flagsa & 0x2000)
  1089. hidden = bool(flagsa & 0x1000)
  1090. hide_guide = bool(flagsa & 0x200)
  1091. service = flagsa & 0x3f
  1092. desc_len &= 0x3ff
  1093. descs = getdescriptors(tb[i:i + desc_len])
  1094. i += desc_len
  1095. self['channels'].append({ 'name': shrtnm,
  1096. 'major': major, 'minor': minor, 'mode': mode,
  1097. 'carrier': carrier, 'tsid': tsid,
  1098. 'prog_num': prog_num, 'source': source,
  1099. 'etm_loc': etm_loc,
  1100. 'access_control': access_control, 'hidden': hidden,
  1101. 'service': service, 'descriptors': descs })
  1102. desc_len = ((ord(tb[i]) & 0x3) << 8) | ord(tb[i + 1])
  1103. i += 2
  1104. self['descriptors'] = getdescriptors(tb[i:i + desc_len])
  1105. def repr_part(self):
  1106. return [ dict.__repr__(self), ]
  1107. class ETT(dict):
  1108. def __init__(self):
  1109. '''In order to prevent confusion, you can't init w/ a packet.'''
  1110. super(ETT, self).__init__()
  1111. def clean_up(self):
  1112. pass
  1113. def __call__(self, psip):
  1114. assert psip.table_id == 0xcc and psip.table[0] == '\x00'
  1115. id, event = struct.unpack('>HH', psip.table[1:5])
  1116. event >>= 2
  1117. desc = MultiStringStruct(psip.table[5:])
  1118. self[(id, event)] = desc
  1119. #print `self`
  1120. def __repr__(self):
  1121. return '<ETT: %s>' % dict.__repr__(self)
  1122. class TSPESHandler:
  1123. def __init__(self, cb):
  1124. self.cb = cb
  1125. self.discontinuity = True
  1126. self.complete = False
  1127. self.last_continuity = None
  1128. self.pes_len = None
  1129. def next_continuity(self, nc):
  1130. if self.last_continuity is None:
  1131. return True
  1132. return ((self.last_continuity + 1) % 16) == nc
  1133. def is_video(self):
  1134. return (self.stream_id & 0xf0) == 0xe0
  1135. def __call__(self, p):
  1136. if p.error:
  1137. #print 'got error:', `p`
  1138. return
  1139. if p.start:
  1140. if self.pes_len == 0:
  1141. assert self.is_video()
  1142. # if we were unbounded, dump the last one
  1143. if self.next_continuity(p.continuity):
  1144. self.cb(''.join(self.stored_sects))
  1145. payload = p.payload
  1146. if payload[:3] != '\x00\x00\x01':
  1147. raise ValueError, 'packet start code invalid'
  1148. self.stream_id = ord(payload[3])
  1149. self.pes_len = (ord(payload[4]) << 8) | ord(payload[5])
  1150. if not self.is_video():
  1151. #print 'pes', hex(self.stream_id), repr(p)
  1152. assert self.pes_len != 0
  1153. # A value of 0 indicates that the PES packet
  1154. # length is neither specified nor bounded and is
  1155. # allowed only in PES packets whose payload is a
  1156. # video elementary stream contained in Transport
  1157. # Stream packets. -- iso-13818-1 Sect. 2.4.3.7
  1158. if self.pes_len != 0:
  1159. self.pes_len += 6 # add in header
  1160. self.stored_sects = [ payload ]
  1161. self.stored_len = len(self.stored_sects[0])
  1162. self.discontinuity = False
  1163. else:
  1164. if self.discontinuity or \
  1165. not self.next_continuity(p.continuity):
  1166. self.discontinuity = True
  1167. return
  1168. self.stored_sects.append(p.payload)
  1169. self.stored_len += len(p.payload)
  1170. self.last_continuity = p.continuity
  1171. if self.stored_len < self.pes_len or self.pes_len == 0:
  1172. return
  1173. ps = ''.join(self.stored_sects)
  1174. assert self.stored_len == self.pes_len and \
  1175. self.pes_len == len(ps)
  1176. self.cb(ps)
  1177. def read_clock(buf):
  1178. assert len(buf) == 6
  1179. base = (long(ord(buf[0])) << 25) | (ord(buf[1]) << 17) | \
  1180. (ord(buf[2]) << 9) | (ord(buf[3]) << 1) | \
  1181. (ord(buf[4]) >> 7)
  1182. extension = ((ord(buf[4]) & 0x1) << 8) | ord(buf[5])
  1183. return (base, extension)
  1184. class SimpleTSPacket:
  1185. def __init__(self, p):
  1186. assert len(p) == TSPKTLEN
  1187. assert p[0] == TSSYNC
  1188. f = ord(p[1])
  1189. self.error = bool(f & 0x80)
  1190. self.start = bool(f & 0x40)
  1191. self.priority = bool(f & 0x20)
  1192. self.pid = ((f & 0x1f) << 8) + ord(p[2])
  1193. if self.pid == 0x1fff:
  1194. return
  1195. f = ord(p[3])
  1196. self.scramble = (f & 0xc0) >> 6
  1197. adapt = (f & 0x30) >> 4
  1198. self.continuity = f & 0xf
  1199. if self.error:
  1200. return
  1201. class TSPacket:
  1202. def __init__(self, *p):
  1203. assert len(p) <= 1
  1204. if len(p) == 0:
  1205. return
  1206. p = p[0]
  1207. origp = p
  1208. assert len(p) == TSPKTLEN
  1209. assert p[0] == TSSYNC
  1210. f = ord(p[1])
  1211. self.error = bool(f & 0x80)
  1212. self.start = bool(f & 0x40)
  1213. self.priority = bool(f & 0x20)
  1214. self.pid = ((f & 0x1f) << 8) + ord(p[2])
  1215. if self.pid == 0x1fff:
  1216. return
  1217. f = ord(p[3])
  1218. self.scramble = (f & 0xc0) >> 6
  1219. adapt = (f & 0x30) >> 4
  1220. self.continuity = f & 0xf
  1221. if self.error:
  1222. return
  1223. i = 4
  1224. adapt_len = ord(p[4])
  1225. # XXX - this is a large adapt, is it real?
  1226. if (adapt >= 2 and adapt_len >= 188) or self.scramble:
  1227. return
  1228. if adapt >= 2:
  1229. if adapt == 3:
  1230. pass
  1231. # see below
  1232. #assert adapt_len >= 0 and adapt_len <= 182
  1233. else:
  1234. pass
  1235. # my reading of the spec says this, but in
  1236. # practice this isn't the case
  1237. #assert adapt == 2 and adapt_len == 183
  1238. buf = p[i + 1:i + 1 + adapt_len]
  1239. #print self.error, self.start, self.priority, self.pid, self.scramble, adapt, self.continuity, adapt_len, i
  1240. #assert len(buf) == adapt_len, 'adapt: %d, lengths: %d, %d, buf[0]: %02x' % (adapt, len(buf), adapt_len, ord(buf[0]))
  1241. try:
  1242. self.decode_adaptation(buf)
  1243. except:
  1244. pass
  1245. # XXX - handle adpatation
  1246. i += 1 + adapt_len
  1247. self.payload = p[i:]
  1248. def decode_adaptation(self, adp):
  1249. if len(adp) == 0:
  1250. return
  1251. self.discontinuity_indicator = bool(ord(adp[0]) & 0x80)
  1252. self.random_access_indicator = bool(ord(adp[0]) & 0x40)
  1253. self.elementary_stream_priority = bool(ord(adp[0]) & 0x20)
  1254. PCR_flag = bool(ord(adp[0]) & 0x10)
  1255. OPCR_flag = bool(ord(adp[0]) & 0x08)
  1256. splicing_point_flag = bool(ord(adp[0]) & 0x04)
  1257. transport_private_data_flag = bool(ord(adp[0]) & 0x02)
  1258. adaptation_field_extension_flag = bool(ord(adp[0]) & 0x01)
  1259. i = 1
  1260. if PCR_flag:
  1261. self.PCR = read_clock(adp[i: i + 6])
  1262. i += 6
  1263. if OPCR_flag:
  1264. self.OPCR = read_clock(adp[i: i + 6])
  1265. i += 6
  1266. if splicing_point_flag:
  1267. self.splice_countdown = ord(adp[i])
  1268. i += 1
  1269. if transport_private_data_flag:
  1270. plen = ord(adp[i])
  1271. self.private_data = adp[i + 1: i + 1 + plen]
  1272. i += 1 + plen
  1273. if adaptation_field_extension_flag:
  1274. alen = ord(adp[i])
  1275. ltw_flag = ord(adp[i + 1]) & 0x80
  1276. piecewise_rate_flag = ord(adp[i + 1]) & 0x40
  1277. seamless_splice_flag = ord(adp[i + 1]) & 0x20
  1278. i += 2
  1279. if ltw_flag:
  1280. self.ltw_valid = bool(ord(adp[i]) & 0x80)
  1281. self.ltw_offset = ((ord(adp[i]) & 0x7f) <<
  1282. 8) | ord(adp[i + 1])
  1283. i += 2
  1284. if piecewise_rate_flag:
  1285. self.piecewise_rate = ((ord(adp[i]) & 0x3f) <<
  1286. 16) | (ord(adp[i + 1]) << 8) | \
  1287. ord(adp[i + 2])
  1288. i += 3
  1289. if seamless_splice_flag:
  1290. self.splice_type = (ord(adp[i]) & 0xf0) >> 4
  1291. self.DTS_next_AU = read_timestamp(adp[i:i + 5])
  1292. def __repr__(self):
  1293. v = ('pid', 'error', 'start', 'continuity', 'priority',
  1294. 'scramble', 'payload', 'discontinuity_indicator',
  1295. 'random_access_indicator', 'elementary_stream_priority',
  1296. 'PCR', 'OPCR', 'splice_countdown', 'private_data',
  1297. 'ltw_valid', 'ltw_offset', 'piecewise_rate', 'splice_type',
  1298. 'DTS_next_AU', )
  1299. return '<TSPacket: %s>' % ', '.join(attribreprlist(self, v))
  1300. def __str__(self):
  1301. '''We may want to save the original packet, and return it until the
  1302. data gets modified.'''
  1303. if self.error:
  1304. return '%c%s' % (TSSYNC, '\xff' * 187)
  1305. sb = (self.pid >> 8) & 0x1f
  1306. if self.error:
  1307. sb |= 0x80
  1308. if self.start:
  1309. sb |= 0x40
  1310. if self.priority:
  1311. sb |= 0x20
  1312. tb = self.pid & 0xff
  1313. fb = ((self.scramble & 0x3) << 6) | (self.continuity & 0xf)
  1314. alenstr = ''
  1315. if self.adaptation:
  1316. fb |= 1 << 5
  1317. alenstr = chr(len(self.adaptation))
  1318. if self.payload:
  1319. fb |= 1 << 4
  1320. ret = '%c%c%c%c%s%s%s' % (TSSYNC, sb, tb, fb, alenstr,
  1321. self.adaptation, self.payload)
  1322. if len(ret) != TSPKTLEN:
  1323. pass
  1324. #print >>sys.stderr, repr(self)
  1325. #print >>sys.stderr, len(self.adaptation), len(self.payload)
  1326. assert len(ret) == TSPKTLEN
  1327. return ret
  1328. class TSPStream:
  1329. '''This class takes a file object, and outputs TS packets.'''
  1330. def __init__(self, f, endpos = None):
  1331. self.f = f
  1332. self.endpos = endpos
  1333. def __iter__(self):
  1334. foundsync = False
  1335. buf = self.f.read(READBLK)
  1336. fppos = self.f.tell()
  1337. while buf:
  1338. if self.endpos is not None and \
  1339. fppos > self.endpos:
  1340. break
  1341. if not foundsync:
  1342. try:
  1343. start = buf.index(TSSYNC)
  1344. except ValueError:
  1345. buf = self.f.read(READBLK)
  1346. fppos = self.f.tell()
  1347. continue
  1348. try:
  1349. if buf[start + TSPKTLEN] == '\x47':
  1350. #if start != 0:
  1351. # print >>sys.stderr, 'sync off:', start, 'data:', repr(buf[:start])
  1352. foundsync = True
  1353. else:
  1354. #print >>sys.stderr, 'drop to sync:', start, 'data:', repr(buf[:start])
  1355. buf = buf[start + 1:]
  1356. continue
  1357. except IndexError:
  1358. nbuf = self.f.read(READBLK)
  1359. fppos = self.f.tell()
  1360. if not nbuf:
  1361. return
  1362. buf += nbuf
  1363. continue
  1364. if buf[start] != '\x47':
  1365. #print >>sys.stderr, 'sync failed'
  1366. foundsync = False
  1367. continue
  1368. t = buf[start:start + TSPKTLEN]
  1369. if len(t) != TSPKTLEN:
  1370. r = self.f.read(READBLK)
  1371. fppos = self.f.tell()
  1372. if not r:
  1373. #No more data
  1374. break
  1375. buf = buf[start:] + r
  1376. start = 0
  1377. if not buf:
  1378. buf = self.f.read(READBLK)
  1379. fppos = self.f.tell()
  1380. continue
  1381. self.itempos = fppos - len(buf)
  1382. yield t
  1383. buf = buf[start + TSPKTLEN:]
  1384. start = 0
  1385. if not buf:
  1386. buf = self.f.read(READBLK)
  1387. fppos = self.f.tell()
  1388. import getopt
  1389. import re
  1390. import sys
  1391. def usage():
  1392. print 'Usage: %s -lmty <mpegtsstream>' % sys.argv[0]
  1393. print ' %s -k <pid> <mpegtsstream>' % sys.argv[0]
  1394. print ' %s -b [ -p ] <mpegtsstream>' % sys.argv[0]
  1395. print ' %s -c <channel> -o <output> <mpegtsstream>' % sys.argv[0]
  1396. print ''
  1397. print ' -l list channels'
  1398. print ' -m print PAT and PMT'
  1399. print ' -t print TVCT'
  1400. print ''
  1401. print ' -b bandwidth'
  1402. print ' -p sort by percentage'
  1403. print ''
  1404. print ' -c channel to capture'
  1405. print ' -o file to output channel'
  1406. print ''
  1407. print ' -k print PCR of pid stream'
  1408. print ''
  1409. print 'Options for all:'
  1410. print ' -y file offset when done'
  1411. print ' -s <start> Starting pos'
  1412. print ' -e <end> Ending pos'
  1413. def findchannel(tvct, chan):
  1414. for i in tvct['channels']:
  1415. if isinstance(chan, int):
  1416. if i['minor'] == chan:
  1417. return i
  1418. elif isinstance(chan, tuple):
  1419. assert len(chan) == 2
  1420. if i['major'] == chan[0] and i['minor'] == chan[1]:
  1421. return i
  1422. else:
  1423. if i['name'] == chan:
  1424. return i
  1425. return None
  1426. def GetTVCT(tsstream):
  1427. listchan = True
  1428. needtvct = True
  1429. needpat = False
  1430. pat = PAT()
  1431. pmts = {}
  1432. tvct = TVCT()
  1433. psippids = { 0x00: TSPSIPHandler({ 0x00: pat }),
  1434. 0x1ffb: TSPSIPHandler({ 0xc8: tvct, }),
  1435. }
  1436. def getpmt(pid, pm = pmts, psp = psippids):
  1437. if not pm.has_key(pid):
  1438. pm[pid] = PMT()
  1439. psp[pid] = TSPSIPHandler({ 0x02: pm[pid] })
  1440. def needpmts(pm = pmts):
  1441. for i in pm.itervalues():
  1442. if not i:
  1443. return True
  1444. return False
  1445. for i in itertools.imap(TSPacket, tsstream):
  1446. try:
  1447. psippids[i.pid](i)
  1448. except ValueError:
  1449. continue
  1450. except KeyError:
  1451. pass
  1452. # XXX - we need to give up finding the TVCT after a while, and
  1453. # pretend we found it w/ some defaults. KCSM doesn't
  1454. # broadcast a TVCT.
  1455. if needtvct and tvct:
  1456. needtvct = False
  1457. needpat = True
  1458. if needpat and pat:
  1459. needpat = False
  1460. for j in pat.itervalues():
  1461. getpmt(j)
  1462. if not (needtvct or needpat or needpmts()):
  1463. break
  1464. try:
  1465. lst = tvct['channels']
  1466. lst.sort(channelmajorminorsort)
  1467. except KeyError:
  1468. # unable to find TVCT
  1469. lst = pat.items()
  1470. lst.sort()
  1471. lst = map(lambda x, y: { 'name': 'PAT%d' % x[1],
  1472. 'prog_num': x[1], 'major': '?', 'minor': y}, lst,
  1473. range(1, len(pat) + 1))
  1474. tvct = { 'channels': lst }
  1475. for i in lst:
  1476. if i['prog_num'] != 0:
  1477. i['PMT'] = pmts[pat[i['prog_num']]]
  1478. i['PMTpid'] = pat[i['prog_num']]
  1479. return tvct
  1480. def main():
  1481. try:
  1482. opts, args = getopt.getopt(sys.argv[1:], "bc:e:hk:lmo:pr:s:ty")
  1483. except getopt.GetoptError:
  1484. # print help information and exit:
  1485. usage()
  1486. sys.exit(2)
  1487. printbyteoffset = False
  1488. printbandwidth = False
  1489. printbandwidthpercent = False
  1490. listchan = False
  1491. channelsel = None
  1492. programsel = None
  1493. output = None
  1494. allmaps = False
  1495. printtvct = False
  1496. startpos = None
  1497. endpos = None
  1498. pcrpid = None
  1499. needtvct = False
  1500. needpat = False
  1501. channelfnd = False
  1502. needallmaps = False
  1503. cuts = False
  1504. for o, a in opts:
  1505. if o == '-b':
  1506. printbandwidth = True
  1507. elif o == "-c":
  1508. try:
  1509. channelsel = int(a)
  1510. except ValueError:
  1511. try:
  1512. channelsel = tuple(map(int,
  1513. re.split('[-.]', a, 1)))
  1514. except ValueError:
  1515. channelsel = a
  1516. if channelsel is not None:
  1517. needpat = True
  1518. needtvct = True
  1519. elif o == '-e':
  1520. endpos = int(a)
  1521. elif o == '-k':
  1522. pcrpid = int(a)
  1523. elif o == "-m":
  1524. allmaps = True
  1525. needallmaps = True
  1526. needpat = True
  1527. elif o == '-s':
  1528. startpos = int(a)
  1529. elif o == '-t':
  1530. printtvct = True
  1531. needtvct = True
  1532. elif o == "-l":
  1533. listchan = True
  1534. needpat = True
  1535. needtvct = True
  1536. elif o in ("-h", "--help"):
  1537. usage()
  1538. sys.exit()
  1539. elif o == '-o':
  1540. output = a
  1541. elif o == '-p':
  1542. printbandwidthpercent = True
  1543. elif o == '-r':
  1544. programsel = int(a)
  1545. needpat = True
  1546. elif o == '-y':
  1547. printbyteoffset = True
  1548. if len(args) != 1 or (channelsel and not output):
  1549. usage()
  1550. sys.exit()
  1551. inp = open(args[0])
  1552. if startpos is not None:
  1553. inp.seek(startpos)
  1554. s = TSPStream(inp, endpos)
  1555. pat = PAT()
  1556. pmts = {}
  1557. tvct = TVCT()
  1558. stt = STT()
  1559. def null(p):
  1560. #print 'null', repr(p)
  1561. pass
  1562. null.clean_up = lambda: None
  1563. psippids = { 0x00: TSPSIPHandler({ 0x00: pat }),
  1564. }
  1565. pidcnt = {}
  1566. mgt = MGT(psippids)
  1567. psippids[0x1ffb] = TSPSIPHandler({
  1568. #0xc7: mgt,
  1569. 0xc8: tvct,
  1570. 0xcd: stt,
  1571. })
  1572. def getpmt(pid, pm = pmts, psp = psippids):
  1573. if not pm.has_key(pid):
  1574. pm[pid] = PMT()
  1575. psp[pid] = TSPSIPHandler({ 0x02: pm[pid] })
  1576. def needpmts(pm = pmts):
  1577. for i in pm.itervalues():
  1578. if not i:
  1579. return True
  1580. return False
  1581. lastpcr = None
  1582. lastpatpos = None
  1583. for i in itertools.imap(TSPacket, s):
  1584. #if hasattr(i, 'splice_countdown') or hasattr(i, 'DTS_next_AU'):
  1585. # print 'splice_countdown:', repr(i)
  1586. #if hasattr(i, 'PCR'):
  1587. # print 'PCR:', repr(i)
  1588. #if i.pid in (48, 64, 80, 112):
  1589. # print `i`
  1590. # print s.itempos, `i`
  1591. if i.pid == 0 or lastpatpos is None:
  1592. lastpatpos = s.itempos
  1593. if pcrpid is not None and i.pid == pcrpid:
  1594. if lastpcr is not None:
  1595. # I've only seen 2703 as the largest
  1596. if i.PCR[0] - lastpcr[0] > 3000:
  1597. print lastpatpos
  1598. lastpcr = i.PCR
  1599. try:
  1600. psippids[i.pid](i)
  1601. except ValueError, x:
  1602. #import traceback
  1603. #print traceback.print_exc()
  1604. print >>sys.stderr, 'bad crc:', repr(i)
  1605. continue
  1606. except KeyError:
  1607. pass
  1608. try:
  1609. pidcnt[i.pid] += 1
  1610. except KeyError:
  1611. pidcnt[i.pid] = 1
  1612. # XXX - we need to give up finding the TVCT after a while, and
  1613. # pretend we found it w/ some defaults. KCSM doesn't
  1614. # broadcast a TVCT.
  1615. if needtvct and tvct:
  1616. # Handle TVCT
  1617. needtvct = False
  1618. if programsel is not None and pat:
  1619. channelfnd = pat[programsel]
  1620. getpmt(channelfnd)
  1621. if channelsel is not None and pat and tvct:
  1622. channelfnd = findchannel(tvct, channelsel)
  1623. if channelfnd is None:
  1624. sys.stderr.write("Unable to find channel: %s\n"
  1625. % channelsel)
  1626. channelsel = None
  1627. else:
  1628. channelfnd = pat[channelfnd['prog_num']]
  1629. getpmt(channelfnd)
  1630. if needpat and pat:
  1631. needpat = False
  1632. for pn, j in pat.iteritems():
  1633. if pn == 0:
  1634. # XXX - NIT
  1635. continue
  1636. if listchan or allmaps:
  1637. getpmt(j)
  1638. if needallmaps and pat and pmts:
  1639. for i in pat.itervalues():
  1640. if not pmts.has_key(i):
  1641. break
  1642. needallmaps = False
  1643. #print `tvct`, `pat`, `pmts`
  1644. #print needtvct, needpat, needpmts(), printbandwidth, needallmaps
  1645. if not (needtvct or needpat or needpmts() or printbandwidth or
  1646. needallmaps or pcrpid):
  1647. break
  1648. if channelfnd and pmts[channelfnd]:
  1649. av = getaudiovideopids(pmts[channelfnd])
  1650. os.system("python tssel.py '%s' %s %s > '%s'" % (args[0],
  1651. channelfnd, ' '.join(map(str, itertools.chain(*av))),
  1652. output))
  1653. if allmaps:
  1654. print repr(pat)
  1655. print repr(pmts)
  1656. if printtvct:
  1657. print repr(tvct)
  1658. if listchan:
  1659. #List channels
  1660. #try:
  1661. lst = tvct['channels']
  1662. lst.sort(channelmajorminorsort)
  1663. #except KeyError:
  1664. # # unable to find TVCT
  1665. # sys.stderr.write("unable to find TVCT table, faking it.\n")
  1666. # lst = pat.items()
  1667. # lst.sort()
  1668. # lst = map(lambda x, y: { 'prog_num': x[1], 'major': '?', 'minor': y}, lst, range(1, len(pat) + 1))
  1669. for i in lst:
  1670. if i['prog_num'] != 0 and i['prog_num'] != 0xffff:
  1671. #print repr(pmts[pat[i['prog_num']]])
  1672. av = getaudiovideopids(pmts[pat[i['prog_num']]])
  1673. prog_info = '\t'.join(map(lambda x:
  1674. ','.join(map(str, x)), av))
  1675. else:
  1676. prog_info = ''
  1677. print ('%(major)d.%(minor)d\t%(name)s\t' % i) + \
  1678. prog_info
  1679. if printbandwidth:
  1680. totpkts = sum(pidcnt.itervalues())
  1681. i = pidcnt.items()
  1682. if printbandwidthpercent:
  1683. def secondfirst(x, y):
  1684. if x[1] == y[1]:
  1685. return cmp(x[0], y[0])
  1686. return cmp(x[1], y[1])
  1687. i.sort(secondfirst)
  1688. else:
  1689. i.sort()
  1690. for pid, cnt in i:
  1691. print '%4d\t%d\t%5.2f' % (pid, cnt,
  1692. float(cnt) * 100 / totpkts)
  1693. if printbyteoffset:
  1694. print inp.tell()
  1695. def justprint(v, p):
  1696. '''v is pid, p is the data'''
  1697. if v != 49:
  1698. return
  1699. pes = PES(p)
  1700. if pes.data[3] != '\x00':
  1701. print `pes`
  1702. return
  1703. fc = findcodes(pes.data)
  1704. print 'justprint', v, len(p), repr(pes), repr(pes.data[:20]), fc
  1705. for i in filter(lambda x: x[1] == '\x00', fc):
  1706. print `pes.data[i[0] + 3: i[0] + 7]`
  1707. if ((ord(pes.data[i[0] + 5]) & 0x38) >> 3) in (2, 3):
  1708. print 'non I frame found: %d' % \
  1709. ((ord(pes.data[i[0] + 5]) & 0x38) >> 3)
  1710. if __name__ == '__main__':
  1711. if True:
  1712. main()
  1713. sys.exit(0)
  1714. if False:
  1715. ps = UnRead(sys.argv[1])
  1716. while ps:
  1717. print `Pack(ps)`
  1718. sys.exit()
  1719. s = TSPStream(open(sys.argv[1]))
  1720. if False:
  1721. cleaned = open(sys.argv[2], 'w')
  1722. for j in s:
  1723. cleaned.write(str(j))
  1724. continue
  1725. sys.exit()
  1726. pids = {}
  1727. skipped = 0
  1728. cont = {}
  1729. count = 0
  1730. pat = PAT()
  1731. pmts = {}
  1732. pesstreams = {}
  1733. tvct = TVCT()
  1734. pidhandlers = { 0x00: TSPSIPHandler({ 0x00: pat }),
  1735. 0x1ffb: TSPSIPHandler({ 0xc8: tvct }),
  1736. }
  1737. first = last = None
  1738. for j in itertools.imap(TSPacket, s):
  1739. count += 1
  1740. if j.pid == 8191 or (j.pid != 0 and j.pid != 48):
  1741. skipped += 1
  1742. continue
  1743. else:
  1744. #if j.pid > 4000:
  1745. #print `j`
  1746. try:
  1747. pidhandlers[j.pid](j)
  1748. except KeyError:
  1749. pass
  1750. except ValueError, x:
  1751. print 'VE:', x
  1752. #if pidhandlers[0x1ffb][0xc8]:
  1753. # print repr(pidhandlers[0x1ffb][0xc8])
  1754. # We should probably cache which ones we've added, and remove
  1755. # Ones that aren't there. Or do a clean_up callback.
  1756. for k in pidhandlers[0][0].itervalues():
  1757. if pmts.has_key(k):
  1758. continue
  1759. pmts[k] = PMT()
  1760. pidhandlers[k] = TSPSIPHandler({ 0x02: pmts[k] })
  1761. for k in itertools.ifilter(lambda x: x.es, pmts.itervalues()):
  1762. #print repr(k)
  1763. for l in k.es:
  1764. if pesstreams.has_key(l[1]):
  1765. continue
  1766. print repr(l)
  1767. pesstreams[l[1]] = TSPESHandler(lambda x, y =
  1768. l[1]: justprint(y, x))
  1769. pidhandlers[l[1]] = pesstreams[l[1]]
  1770. try:
  1771. if (cont[j.pid] + 1) % 16 != j.continuity:
  1772. pass
  1773. #print 'continuity failed'
  1774. cont[j.pid] = j.continuity
  1775. except KeyError:
  1776. cont[j.pid] = j.continuity
  1777. try:
  1778. pids[j.pid] += 1
  1779. except KeyError:
  1780. pids[j.pid] = 1
  1781. p = pids.items()
  1782. p.sort()
  1783. print p
  1784. print 'skipped:', skipped
  1785. print 'total:', count