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.

638 lines
18 KiB

  1. import array
  2. import string
  3. import UserDict
  4. from ctypes import *
  5. # Find out if we need to endian swap the buffer
  6. t = array.array('H', '\x00\x01')
  7. if t[0] == 1:
  8. is_little_endian = False
  9. else:
  10. is_little_endian = True
  11. del t
  12. interleavelib = CDLL('./_interleave.so')
  13. inter = {}
  14. for i in (16, ):
  15. f = getattr(interleavelib, 'interleave%d' % i)
  16. f.restype = None
  17. # bigendian, nchan, chanmap, chansamps, data, out
  18. outtype = locals()['c_int%d' % i]
  19. f.argtypes = [ c_int, POINTER(c_int), c_int,
  20. POINTER(POINTER(c_int32)), POINTER(outtype), ]
  21. inter[i] = outtype, f
  22. flaclib = CDLL('libFLAC.so')
  23. # Defines
  24. FLAC__METADATA_TYPE_STREAMINFO = 0
  25. FLAC__METADATA_TYPE_PADDING = 1
  26. FLAC__METADATA_TYPE_APPLICATION = 2
  27. FLAC__METADATA_TYPE_SEEKTABLE = 3
  28. FLAC__METADATA_TYPE_VORBIS_COMMENT = 4
  29. FLAC__METADATA_TYPE_CUESHEET = 5
  30. FLAC__METADATA_TYPE_PICTURE = 6
  31. FLAC__METADATA_TYPE_UNDEFINED = 7
  32. FLAC__MAX_CHANNELS = 8
  33. FLAC__MAX_LPC_ORDER = 32
  34. FLAC__MAX_FIXED_ORDER = 4
  35. # Data
  36. FLAC__StreamDecoderStateString = (c_char_p * 10).in_dll(flaclib,
  37. 'FLAC__StreamDecoderStateString')
  38. FLAC__StreamDecoderInitStatusString = (c_char_p * 6).in_dll(flaclib,
  39. 'FLAC__StreamDecoderInitStatusString')
  40. FLAC__StreamDecoderErrorStatusString = (c_char_p * 4).in_dll(flaclib,
  41. 'FLAC__StreamDecoderErrorStatusString')
  42. # Enums
  43. FLAC__STREAM_DECODER_SEARCH_FOR_METADATA = 0
  44. FLAC__STREAM_DECODER_READ_METADATA = 1
  45. FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC = 2
  46. FLAC__STREAM_DECODER_READ_FRAME = 3
  47. FLAC__STREAM_DECODER_END_OF_STREAM = 4
  48. FLAC__STREAM_DECODER_OGG_ERROR = 5
  49. FLAC__STREAM_DECODER_SEEK_ERROR = 6
  50. FLAC__STREAM_DECODER_ABORTED = 7
  51. FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR = 8
  52. FLAC__STREAM_DECODER_UNINITIALIZED = 9
  53. FLAC__STREAM_DECODER_INIT_STATUS_OK = 0
  54. FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER = 0
  55. FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER = 1
  56. FLAC__SUBFRAME_TYPE_CONSTANT = 0
  57. FLAC__SUBFRAME_TYPE_VERBATIM = 1
  58. FLAC__SUBFRAME_TYPE_FIXED = 2
  59. FLAC__SUBFRAME_TYPE_LPC = 3
  60. OrigStructure = Structure
  61. class Structure(Structure):
  62. def getarray(self, base):
  63. base_array = getattr(self, base)
  64. return [ base_array[x] for x in xrange(getattr(self,
  65. 'num_' + base)) ]
  66. def __getattr__(self, k):
  67. if k[-6:] == '_array':
  68. return self.getarray(k[:-6])
  69. raise AttributeError(k)
  70. def asobj(self):
  71. r = {}
  72. #print 'asobj:', `self`
  73. if hasattr(self, '_material_'):
  74. flds = self._material_
  75. else:
  76. flds = self._fields_
  77. for i in flds:
  78. attr = i[0]
  79. obj = getattr(self, attr)
  80. if attr[-6:] == '_array':
  81. #print 'asarraycnt'
  82. v = [ x.asobj() for x in
  83. self.getarray(attr[:-6]) ]
  84. elif isinstance(obj, Structure):
  85. #print 'asstruct'
  86. v = obj.asobj()
  87. elif isinstance(obj, Array) and obj._type_ != c_char:
  88. #print 'asarray'
  89. v = obj[:]
  90. else:
  91. #print 'asobj'
  92. v = obj
  93. r[attr] = v
  94. return r
  95. def __repr__(self, fields=None):
  96. cls = self.__class__
  97. if fields is None:
  98. fields = self._fields_
  99. return '<%s.%s: %s>' % (cls.__module__, cls.__name__,
  100. ', '.join([ '%s: %s' % (x[0], `getattr(self, x[0])`)
  101. for x in fields ]))
  102. class FLAC__StreamMetadata_StreamInfo(Structure):
  103. _fields_ = [ ('min_blocksize', c_uint),
  104. ('max_blocksize', c_uint),
  105. ('min_framesize', c_uint),
  106. ('max_framesize', c_uint),
  107. ('sample_rate', c_uint),
  108. ('channels', c_uint),
  109. ('bits_per_sample', c_uint),
  110. ('total_samples', c_uint64),
  111. ('md5sum', c_ubyte * 16),
  112. ]
  113. class FLAC__StreamMetadata_VorbisComment_Entry(Structure):
  114. _fields_ = [ ('length', c_uint32),
  115. ('entry', POINTER(c_char)), # string bounded by length
  116. ]
  117. def asstring(self):
  118. return self.entry[:self.length].decode('utf-8')
  119. def __repr__(self):
  120. return '<FLAC__StreamMetadata_VorbisComment_Entry: %s>' % \
  121. `self.asstring()`
  122. def makestrrange(a, b):
  123. '''Make a string w/ characters from a through b (inclusive).'''
  124. return ''.join(chr(x) for x in xrange(a, b + 1))
  125. class VorbisComments(UserDict.DictMixin):
  126. def __init__(self, vc=()):
  127. d = self._dict = {}
  128. for i in vc:
  129. k, v = i.split('=', 1)
  130. try:
  131. self[k].append(v)
  132. except KeyError:
  133. d[self.makevalidkey(k)] = [ v ]
  134. transtable = string.maketrans(makestrrange(0x41, 0x5a),
  135. makestrrange(0x61, 0x7a))
  136. delchars = makestrrange(0, 0x1f) + '=' + makestrrange(0x7e, 0x7f)
  137. @staticmethod
  138. def makevalidkey(k):
  139. k = str(k)
  140. origlen = len(k)
  141. k = k.translate(VorbisComments.transtable,
  142. VorbisComments.delchars)
  143. if len(k) != origlen:
  144. raise ValueError('Invalid key')
  145. return k
  146. def __getitem__(self, k):
  147. return self._dict[self.makevalidkey(k)]
  148. def __setitem__(self, k, v):
  149. # XXX - allow? check v?
  150. return self._dict.__setitem__(self.makevalidkey(k), v)
  151. def __delitem__(self, k):
  152. return self._dict.__delitem__(self.makevalidkey(k))
  153. def keys(self):
  154. return self._dict.keys()
  155. class FLAC__StreamMetadata_VorbisComment(Structure):
  156. _fields_ = [ ('vendor_string',
  157. FLAC__StreamMetadata_VorbisComment_Entry),
  158. ('num_comments', c_uint32),
  159. ('comments', POINTER(FLAC__StreamMetadata_VorbisComment_Entry)),
  160. ]
  161. _material_ = (('vendor_string', ), ('comments_array', ))
  162. def asobj(self):
  163. return self.vendor_string.asstring(), \
  164. VorbisComments(x.asstring() for x in
  165. self.getarray('comments'))
  166. def __repr__(self):
  167. return Structure.__repr__(self, self._material_)
  168. class FLAC__StreamMetadata_CueSheet_Index(Structure):
  169. _fields_ = [ ('offset', c_uint64),
  170. ('number', c_ubyte),
  171. ]
  172. class FLAC__StreamMetadata_CueSheet_Track(Structure):
  173. _fields_ = [ ('offset', c_uint64),
  174. ('number', c_ubyte),
  175. ('isrc', c_char * 13), # string + NUL
  176. ('type', c_ubyte, 1),
  177. ('pre_emphasis', c_ubyte, 1),
  178. ('num_indices', c_ubyte),
  179. ('indices', POINTER(FLAC__StreamMetadata_CueSheet_Index)),
  180. ]
  181. _material_ = (('offset', ), ('number', ), ('isrc', ), ('type', ),
  182. ('pre_emphasis', ), ('indices_array', ))
  183. def __repr__(self):
  184. return Structure.__repr__(self, self._material_)
  185. class FLAC__StreamMetadata_CueSheet(Structure):
  186. _fields_ = [ ('media_catalog_number', c_char * 129), # string + nul
  187. ('lead_in', c_uint64),
  188. ('is_cd', c_int),
  189. ('num_tracks', c_uint),
  190. ('tracks', POINTER(FLAC__StreamMetadata_CueSheet_Track)),
  191. ]
  192. _material_ = (('media_catalog_number', ), ('lead_in', ), ('is_cd', ),
  193. ('tracks_array', ))
  194. def __repr__(self):
  195. return Structure.__repr__(self, self._material_)
  196. class FLAC__StreamMetadataData(Union):
  197. _fields_ = [ ('stream_info', FLAC__StreamMetadata_StreamInfo),
  198. ('vorbis_comment', FLAC__StreamMetadata_VorbisComment),
  199. ('cue_sheet', FLAC__StreamMetadata_CueSheet),
  200. ]
  201. class FLAC__StreamMetadata(Structure):
  202. _fields_ = [ ('type', c_int),
  203. ('is_last', c_int),
  204. ('length', c_uint),
  205. ('data', FLAC__StreamMetadataData),
  206. ]
  207. class FLAC__EntropyCodingMethod_PartitionedRiceContents(Structure):
  208. pass
  209. class FLAC__EntropyCodingMethod_PartitionedRice(Structure):
  210. _fields_ = [ ('order', c_uint),
  211. ('contents',
  212. POINTER(FLAC__EntropyCodingMethod_PartitionedRiceContents)),
  213. ]
  214. class FLAC__EntropyCodingMethod(Structure):
  215. _fields_ = [ ('type', c_int),
  216. ('partitioned_rice', FLAC__EntropyCodingMethod_PartitionedRice),
  217. ]
  218. class FLAC__Subframe_Constant(Structure):
  219. _fields_ = [ ('value', c_int32), ]
  220. class FLAC__Subframe_Verbatim(Structure):
  221. _fields_ = [ ('data', POINTER(c_int32)), ]
  222. class FLAC__Subframe_Fixed(Structure):
  223. _fields_ = [ ('entropy_coding_method', FLAC__EntropyCodingMethod),
  224. ('order', c_uint),
  225. ('warmup', c_int32 * FLAC__MAX_FIXED_ORDER),
  226. ('residual', POINTER(c_int32)),
  227. ]
  228. class FLAC__Subframe_LPC(Structure):
  229. _fields_ = [ ('entropy_coding_method', FLAC__EntropyCodingMethod),
  230. ('order', c_uint),
  231. ('qlp_coeff_precision', c_uint),
  232. ('quantization_level', c_int),
  233. ('qlp_coeff', c_int32 * FLAC__MAX_LPC_ORDER),
  234. ('warmup', c_int32 * FLAC__MAX_LPC_ORDER),
  235. ('residual', POINTER(c_int32)),
  236. ]
  237. class FLAC__SubframeUnion(Union):
  238. _fields_ = [ ('constant', FLAC__Subframe_Constant),
  239. ('fixed', FLAC__Subframe_Fixed),
  240. ('lpc', FLAC__Subframe_LPC),
  241. ('verbatim', FLAC__Subframe_Verbatim),
  242. ]
  243. class FLAC__Subframe(Structure):
  244. _fields_ = [ ('type', c_int),
  245. ('data', FLAC__SubframeUnion),
  246. ('wasted_bits', c_uint),
  247. ]
  248. class number_union(Union):
  249. _fields_ = [ ('frame_number', c_uint32),
  250. ('sample_number', c_uint64),
  251. ]
  252. class FLAC__FrameHeader(Structure):
  253. _fields_ = [ ('blocksize', c_uint),
  254. ('sample_rate', c_uint),
  255. ('channels', c_uint),
  256. ('channel_assignment', c_int),
  257. ('bits_per_sample', c_uint),
  258. ('number_type', c_int),
  259. ('number', number_union),
  260. ('crc', c_uint8),
  261. ]
  262. class FLAC__FrameFooter(Structure):
  263. _fields_ = [ ('crc', c_uint16), ]
  264. class FLAC__Frame(Structure):
  265. _fields_ = [ ('header', FLAC__FrameHeader),
  266. ('subframes', FLAC__Subframe * FLAC__MAX_CHANNELS),
  267. ('footer', FLAC__FrameFooter),
  268. ]
  269. class FLAC__StreamDecoder(Structure):
  270. pass
  271. # Types
  272. FLAC__StreamMetadata_p = POINTER(FLAC__StreamMetadata)
  273. FLAC__Frame_p = POINTER(FLAC__Frame)
  274. FLAC__StreamDecoder_p = POINTER(FLAC__StreamDecoder)
  275. # Function typedefs
  276. FLAC__StreamDecoderReadCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  277. POINTER(c_ubyte), POINTER(c_size_t), c_void_p)
  278. FLAC__StreamDecoderSeekCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  279. c_uint64, c_void_p)
  280. FLAC__StreamDecoderTellCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  281. POINTER(c_uint64), c_void_p)
  282. FLAC__StreamDecoderLengthCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  283. POINTER(c_uint64), c_void_p)
  284. FLAC__StreamDecoderEofCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  285. c_void_p)
  286. FLAC__StreamDecoderWriteCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  287. FLAC__Frame_p, POINTER(POINTER(c_int32)), c_void_p)
  288. FLAC__StreamDecoderMetadataCallback = CFUNCTYPE(None, FLAC__StreamDecoder_p,
  289. FLAC__StreamMetadata_p, c_void_p)
  290. FLAC__StreamDecoderErrorCallback = CFUNCTYPE(None, FLAC__StreamDecoder_p,
  291. c_int, c_void_p)
  292. funs = {
  293. 'FLAC__stream_decoder_new': (FLAC__StreamDecoder_p, []),
  294. 'FLAC__stream_decoder_delete': (None, [FLAC__StreamDecoder_p, ]),
  295. 'FLAC__stream_decoder_set_md5_checking': (c_int,
  296. [ FLAC__StreamDecoder_p, c_int, ]),
  297. 'FLAC__stream_decoder_set_metadata_respond': (c_int,
  298. [ FLAC__StreamDecoder_p, c_int, ]),
  299. 'FLAC__stream_decoder_set_metadata_respond_all': (c_int,
  300. [ FLAC__StreamDecoder_p, ]),
  301. 'FLAC__stream_decoder_get_state': (c_int,
  302. [ FLAC__StreamDecoder_p, ]),
  303. 'FLAC__stream_decoder_get_total_samples': (c_uint64,
  304. [ FLAC__StreamDecoder_p, ]),
  305. 'FLAC__stream_decoder_get_channels': (c_uint,
  306. [ FLAC__StreamDecoder_p, ]),
  307. 'FLAC__stream_decoder_get_channel_assignment': (c_int,
  308. [ FLAC__StreamDecoder_p, ]),
  309. 'FLAC__stream_decoder_get_bits_per_sample': (c_uint,
  310. [ FLAC__StreamDecoder_p, ]),
  311. 'FLAC__stream_decoder_get_sample_rate': (c_uint,
  312. [ FLAC__StreamDecoder_p, ]),
  313. 'FLAC__stream_decoder_get_blocksize': (c_uint,
  314. [ FLAC__StreamDecoder_p, ]),
  315. 'FLAC__stream_decoder_init_stream': (c_int, [ FLAC__StreamDecoder_p,
  316. FLAC__StreamDecoderReadCallback, FLAC__StreamDecoderSeekCallback,
  317. FLAC__StreamDecoderTellCallback, FLAC__StreamDecoderLengthCallback,
  318. FLAC__StreamDecoderEofCallback, FLAC__StreamDecoderWriteCallback,
  319. FLAC__StreamDecoderMetadataCallback,
  320. FLAC__StreamDecoderErrorCallback, ]),
  321. 'FLAC__stream_decoder_init_file': (c_int, [ FLAC__StreamDecoder_p,
  322. c_char_p, FLAC__StreamDecoderWriteCallback,
  323. FLAC__StreamDecoderMetadataCallback,
  324. FLAC__StreamDecoderErrorCallback, c_void_p, ]),
  325. 'FLAC__stream_decoder_finish': (c_int, [ FLAC__StreamDecoder_p, ]),
  326. 'FLAC__stream_decoder_flush': (c_int, [ FLAC__StreamDecoder_p, ]),
  327. 'FLAC__stream_decoder_reset': (c_int, [ FLAC__StreamDecoder_p, ]),
  328. 'FLAC__stream_decoder_process_single': (c_int,
  329. [ FLAC__StreamDecoder_p, ]),
  330. 'FLAC__stream_decoder_process_until_end_of_metadata': (c_int,
  331. [ FLAC__StreamDecoder_p, ]),
  332. 'FLAC__stream_decoder_process_until_end_of_stream': (c_int,
  333. [ FLAC__StreamDecoder_p, ]),
  334. 'FLAC__stream_decoder_seek_absolute': (c_int,
  335. [ FLAC__StreamDecoder_p, c_uint64, ]),
  336. }
  337. for i in funs:
  338. f = getattr(flaclib, i)
  339. f.restype, f.argtypes = funs[i]
  340. def clientdatawrapper(fun):
  341. def newfun(*args):
  342. #print 'nf:', `args`
  343. return fun(*args[1:-1])
  344. return newfun
  345. class FLACDec(object):
  346. channels = property(lambda x: x._channels)
  347. samplerate = property(lambda x: x._samplerate)
  348. bitspersample = property(lambda x: x._bitspersample)
  349. totalsamples = property(lambda x: x._totalsamples)
  350. bytespersample = property(lambda x: x._bytespersample)
  351. def __len__(self):
  352. return self._total_samps
  353. def __init__(self, file):
  354. self.flacdec = None
  355. self._lasterror = None
  356. # We need to keep references to the callback functions
  357. # around so they won't be garbage collected.
  358. self.write_wrap = FLAC__StreamDecoderWriteCallback(
  359. clientdatawrapper(self.cb_write))
  360. self.metadata_wrap = FLAC__StreamDecoderMetadataCallback(
  361. clientdatawrapper(self.cb_metadata))
  362. self.error_wrap = FLAC__StreamDecoderErrorCallback(
  363. clientdatawrapper(self.cb_error))
  364. self.flacdec = flaclib.FLAC__stream_decoder_new()
  365. if self.flacdec == 0:
  366. raise RuntimeError('allocating decoded')
  367. flaclib.FLAC__stream_decoder_set_md5_checking(self.flacdec,
  368. True)
  369. flaclib.FLAC__stream_decoder_set_metadata_respond(self.flacdec,
  370. FLAC__METADATA_TYPE_VORBIS_COMMENT)
  371. flaclib.FLAC__stream_decoder_set_metadata_respond(self.flacdec,
  372. FLAC__METADATA_TYPE_CUESHEET)
  373. status = flaclib.FLAC__stream_decoder_init_file(self.flacdec,
  374. file, self.write_wrap, self.metadata_wrap,
  375. self.error_wrap, None)
  376. if status != FLAC__STREAM_DECODER_INIT_STATUS_OK:
  377. raise ValueError(
  378. FLAC__StreamDecoderInitStatusString[status])
  379. self.vorbis = None
  380. self.cuesheet = None
  381. flaclib.FLAC__stream_decoder_process_until_end_of_metadata(
  382. self.flacdec)
  383. if self._lasterror is not None:
  384. raise ValueError(
  385. FLAC__StreamDecoderErrorStatusString[
  386. self._lasterror])
  387. self.curcnt = 0
  388. self.cursamp = 0
  389. if self.vorbis is None:
  390. self.vorbis = '', VorbisComments()
  391. def close(self):
  392. if self.flacdec is None:
  393. return
  394. #print 'close called'
  395. if not flaclib.FLAC__stream_decoder_finish(self.flacdec):
  396. md5invalid = True
  397. else:
  398. md5invalid = False
  399. flaclib.FLAC__stream_decoder_delete(self.flacdec)
  400. self.flacdec = None
  401. self.write_wrap = None
  402. self.metadata_wrap = None
  403. self.error_wrap = None
  404. if md5invalid:
  405. pass
  406. #raise ValueError('invalid md5')
  407. def cb_write(self, frame_p, buffer_pp):
  408. frame = frame_p[0]
  409. #print 'write:', `frame`
  410. #for i in xrange(frame.header.channels):
  411. # print '%d:' % i, `frame.subframes[i]`
  412. nchan = frame.header.channels
  413. #print 'sample number:', frame.header.number.sample_number
  414. self.cursamp = frame.header.number.sample_number
  415. self.curcnt = frame.header.blocksize
  416. if True:
  417. outtype, fun = inter[frame.header.bits_per_sample]
  418. outbuf = (outtype * (nchan * frame.header.blocksize))()
  419. # nchan, chanmap, chansamps, data, out
  420. assert nchan == 2
  421. fun(nchan, (c_int * 2)(0, 1),
  422. frame.header.blocksize, buffer_pp, outbuf)
  423. self.curdata = array.array('h', outbuf)
  424. if is_little_endian:
  425. self.curdata.byteswap()
  426. elif frame.header.bits_per_sample == 16:
  427. self.curdata = array.array('h',
  428. [ buffer_pp[x % nchan][x / nchan] for x in
  429. xrange(frame.header.blocksize * nchan)])
  430. if is_little_endian:
  431. self.curdata.byteswap()
  432. else:
  433. print 'ERROR!'
  434. return 0
  435. def cb_metadata(self, metadata_p):
  436. md = metadata_p[0]
  437. #print 'metadata:', `md`
  438. if md.type == FLAC__METADATA_TYPE_STREAMINFO:
  439. si = md.data.stream_info
  440. self._channels = si.channels
  441. self._samplerate = si.sample_rate
  442. self._bitspersample = si.bits_per_sample
  443. self._totalsamples = si.total_samples
  444. self._bytespersample = si.channels * \
  445. si.bits_per_sample / 8
  446. #print `si`
  447. elif md.type == FLAC__METADATA_TYPE_VORBIS_COMMENT:
  448. self.vorbis = md.data.vorbis_comment.asobj()
  449. #print 'vc:', `md.data.vorbis_comment`
  450. #print 'v:', `self.vorbis`
  451. elif md.type == FLAC__METADATA_TYPE_CUESHEET:
  452. self.cuesheet = md.data.cue_sheet.asobj()
  453. #print 'cs:', `md.data.cue_sheet`
  454. #print 'c:', `self.cuesheet`
  455. else:
  456. print 'unknown metatype:', md.type
  457. def cb_error(self, errstatus):
  458. #print 'error:', `errstatus`
  459. self._lasterror = errstatus
  460. def getstate(self):
  461. state = flaclib.FLAC__stream_decoder_get_state(self.flacdec)
  462. return state
  463. state = property(getstate)
  464. def goto(self, pos):
  465. if self.flacdec is None:
  466. raise ValueError('closed')
  467. pos = min(self.totalsamples - 1, pos)
  468. if flaclib.FLAC__stream_decoder_seek_absolute(self.flacdec,
  469. pos):
  470. return
  471. # the slow way
  472. state = self.state
  473. if state == FLAC__STREAM_DECODER_SEEK_ERROR:
  474. print 'WARNING: possibly invalid file!'
  475. if self.cursamp > pos or \
  476. state == FLAC__STREAM_DECODER_SEEK_ERROR:
  477. if not flaclib.FLAC__stream_decoder_reset(self.flacdec):
  478. raise RuntimeError('unable to seek to beginin')
  479. flaclib.FLAC__stream_decoder_process_until_end_of_metadata(self.flacdec)
  480. flaclib.FLAC__stream_decoder_process_single(
  481. self.flacdec)
  482. read = pos - self.cursamp
  483. while read:
  484. tread = min(read, 512*1024)
  485. self.read(tread)
  486. read -= tread
  487. def read(self, nsamp=16*1024, oneblk=False):
  488. '''If oneblk is True, we will only process data once.'''
  489. if self.flacdec is None:
  490. raise ValueError('closed')
  491. r = []
  492. nsamp = min(nsamp, self.totalsamples - self.cursamp)
  493. nchan = self.channels
  494. while nsamp:
  495. if self.curcnt == 0:
  496. flaclib.FLAC__stream_decoder_process_single(
  497. self.flacdec)
  498. continue
  499. cnt = min(nsamp, self.curcnt)
  500. sampcnt = cnt * nchan
  501. r.append(self.curdata[:sampcnt].tostring())
  502. self.cursamp += cnt
  503. self.curcnt -= cnt
  504. self.curdata = self.curdata[sampcnt:]
  505. nsamp -= cnt
  506. if oneblk:
  507. break
  508. return ''.join(r)
  509. def doprofile(d):
  510. def readtoend():
  511. while d.read():
  512. pass
  513. import hotshot.stats
  514. prof = hotshot.Profile('decread.prof')
  515. prof.runcall(readtoend)
  516. prof.close()
  517. stats = hotshot.stats.load('decread.prof')
  518. stats.strip_dirs()
  519. stats.sort_stats('time', 'calls')
  520. stats.print_stats(20)
  521. if __name__ == '__main__':
  522. import sys
  523. if len(sys.argv) == 1:
  524. print 'Usage: %s <file>' % sys.argv[0]
  525. sys.exit(1)
  526. d = FLACDec(sys.argv[1])
  527. print 'total samples:', d.totalsamples
  528. print 'channels:', d.channels
  529. print 'rate:', d.samplerate
  530. print 'bps:', d.bitspersample
  531. print `d.read(10)`
  532. print 'going'
  533. d.goto(d.totalsamples - 1000*1000)
  534. print 'here'
  535. print `d.read(10)`
  536. doprofile(d)