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.

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