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.

1620 lines
44 KiB

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