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.

382 lines
11 KiB

  1. import array
  2. from ctypes import *
  3. # Find out if we need to endian swap the buffer
  4. t = array.array('H', '\x00\x01')
  5. if t[0] == 1:
  6. is_little_endian = False
  7. else:
  8. is_little_endian = True
  9. del t
  10. flaclib = CDLL('libFLAC.so')
  11. # Defines
  12. FLAC__MAX_CHANNELS = 8
  13. FLAC__MAX_LPC_ORDER = 32
  14. FLAC__MAX_FIXED_ORDER = 4
  15. # Data
  16. FLAC__StreamDecoderInitStatusString = (c_char_p * 6).in_dll(flaclib,
  17. 'FLAC__StreamDecoderInitStatusString')
  18. FLAC__StreamDecoderErrorStatusString = (c_char_p * 4).in_dll(flaclib,
  19. 'FLAC__StreamDecoderErrorStatusString')
  20. # Enums
  21. FLAC__STREAM_DECODER_INIT_STATUS_OK = 0
  22. FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER = 0
  23. FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER = 1
  24. FLAC__SUBFRAME_TYPE_CONSTANT = 0
  25. FLAC__SUBFRAME_TYPE_VERBATIM = 1
  26. FLAC__SUBFRAME_TYPE_FIXED = 2
  27. FLAC__SUBFRAME_TYPE_LPC = 3
  28. class Structure(Structure):
  29. def __repr__(self):
  30. cls = self.__class__
  31. return '<%s.%s: %s>' % (cls.__module__, cls.__name__,
  32. ', '.join([ '%s: %s' % (x, `getattr(self, x)`) for x, t in
  33. self._fields_ ]))
  34. class FLAC__StreamMetadata_StreamInfo(Structure):
  35. _fields_ = [ ('min_blocksize', c_uint),
  36. ('max_blocksize', c_uint),
  37. ('min_framesize', c_uint),
  38. ('max_framesize', c_uint),
  39. ('sample_rate', c_uint),
  40. ('channels', c_uint),
  41. ('bits_per_sample', c_uint),
  42. ('total_samples', c_uint64),
  43. ('md5sum', c_byte * 16),
  44. ]
  45. class FLAC__StreamMetadataData(Union):
  46. _fields_ = [ ('stream_info', FLAC__StreamMetadata_StreamInfo),
  47. ]
  48. class FLAC__StreamMetadata(Structure):
  49. _fields_ = [ ('type', c_int),
  50. ('is_last', c_int),
  51. ('length', c_uint),
  52. ('data', FLAC__StreamMetadataData),
  53. ]
  54. class FLAC__EntropyCodingMethod_PartitionedRiceContents(Structure):
  55. pass
  56. class FLAC__EntropyCodingMethod_PartitionedRice(Structure):
  57. _fields_ = [ ('order', c_uint),
  58. ('contents', POINTER(FLAC__EntropyCodingMethod_PartitionedRiceContents)),
  59. ]
  60. class FLAC__EntropyCodingMethod(Structure):
  61. _fields_ = [ ('type', c_int),
  62. ('partitioned_rice', FLAC__EntropyCodingMethod_PartitionedRice),
  63. ]
  64. class FLAC__Subframe_Constant(Structure):
  65. _fields_ = [ ('value', c_int32),
  66. ]
  67. class FLAC__Subframe_Verbatim(Structure):
  68. _fields_ = [ ('data', POINTER(c_int32)),
  69. ]
  70. class FLAC__Subframe_Fixed(Structure):
  71. _fields_ = [ ('entropy_coding_method', FLAC__EntropyCodingMethod),
  72. ('order', c_uint),
  73. ('warmup', c_int32 * FLAC__MAX_FIXED_ORDER),
  74. ('residual', POINTER(c_int32)),
  75. ]
  76. class FLAC__Subframe_LPC(Structure):
  77. _fields_ = [ ('entropy_coding_method', FLAC__EntropyCodingMethod),
  78. ('order', c_uint),
  79. ('qlp_coeff_precision', c_uint),
  80. ('quantization_level', c_int),
  81. ('qlp_coeff', c_int32 * FLAC__MAX_LPC_ORDER),
  82. ('warmup', c_int32 * FLAC__MAX_LPC_ORDER),
  83. ('residual', POINTER(c_int32)),
  84. ]
  85. class FLAC__SubframeUnion(Union):
  86. _fields_ = [ ('constant', FLAC__Subframe_Constant),
  87. ('fixed', FLAC__Subframe_Fixed),
  88. ('lpc', FLAC__Subframe_LPC),
  89. ('verbatim', FLAC__Subframe_Verbatim),
  90. ]
  91. class FLAC__Subframe(Structure):
  92. _fields_ = [ ('type', c_int),
  93. ('data', FLAC__SubframeUnion),
  94. ('wasted_bits', c_uint),
  95. ]
  96. class number_union(Union):
  97. _fields_ = [ ('frame_number', c_uint32),
  98. ('sample_number', c_uint64),
  99. ]
  100. class FLAC__FrameHeader(Structure):
  101. _fields_ = [ ('blocksize', c_uint),
  102. ('sample_rate', c_uint),
  103. ('channels', c_uint),
  104. ('channel_assignment', c_int),
  105. ('bits_per_sample', c_uint),
  106. ('number_type', c_int),
  107. ('number', number_union),
  108. ('crc', c_uint8),
  109. ]
  110. class FLAC__FrameFooter(Structure):
  111. _fields_ = [ ('crc', c_uint16), ]
  112. class FLAC__Frame(Structure):
  113. _fields_ = [ ('header', FLAC__FrameHeader),
  114. ('subframes', FLAC__Subframe * FLAC__MAX_CHANNELS),
  115. ('footer', FLAC__FrameFooter),
  116. ]
  117. class FLAC__StreamDecoder(Structure):
  118. pass
  119. # Types
  120. FLAC__StreamMetadata_p = POINTER(FLAC__StreamMetadata)
  121. FLAC__Frame_p = POINTER(FLAC__Frame)
  122. FLAC__StreamDecoder_p = POINTER(FLAC__StreamDecoder)
  123. # Function typedefs
  124. FLAC__StreamDecoderReadCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  125. POINTER(c_byte), POINTER(c_size_t), c_void_p)
  126. FLAC__StreamDecoderSeekCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  127. c_uint64, c_void_p)
  128. FLAC__StreamDecoderTellCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  129. POINTER(c_uint64), c_void_p)
  130. FLAC__StreamDecoderLengthCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  131. POINTER(c_uint64), c_void_p)
  132. FLAC__StreamDecoderEofCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  133. c_void_p)
  134. FLAC__StreamDecoderWriteCallback = CFUNCTYPE(c_int, FLAC__StreamDecoder_p,
  135. FLAC__Frame_p, POINTER(POINTER(c_int32)), c_void_p)
  136. FLAC__StreamDecoderMetadataCallback = CFUNCTYPE(None, FLAC__StreamDecoder_p,
  137. FLAC__StreamMetadata_p, c_void_p)
  138. FLAC__StreamDecoderErrorCallback = CFUNCTYPE(None, FLAC__StreamDecoder_p,
  139. c_int, c_void_p)
  140. funs = {
  141. 'FLAC__stream_decoder_new': (FLAC__StreamDecoder_p, []),
  142. 'FLAC__stream_decoder_delete': (None, [FLAC__StreamDecoder_p, ]),
  143. 'FLAC__stream_decoder_set_md5_checking': (c_int,
  144. [ FLAC__StreamDecoder_p, c_int, ]),
  145. 'FLAC__stream_decoder_set_metadata_respond_all': (c_int,
  146. [ FLAC__StreamDecoder_p, ]),
  147. 'FLAC__stream_decoder_get_total_samples': (c_uint64,
  148. [ FLAC__StreamDecoder_p, ]),
  149. 'FLAC__stream_decoder_get_channels': (c_uint,
  150. [ FLAC__StreamDecoder_p, ]),
  151. 'FLAC__stream_decoder_get_channel_assignment': (c_int,
  152. [ FLAC__StreamDecoder_p, ]),
  153. 'FLAC__stream_decoder_get_bits_per_sample': (c_uint,
  154. [ FLAC__StreamDecoder_p, ]),
  155. 'FLAC__stream_decoder_get_sample_rate': (c_uint,
  156. [ FLAC__StreamDecoder_p, ]),
  157. 'FLAC__stream_decoder_get_blocksize': (c_uint,
  158. [ FLAC__StreamDecoder_p, ]),
  159. 'FLAC__stream_decoder_init_stream': (c_int, [ FLAC__StreamDecoder_p,
  160. FLAC__StreamDecoderReadCallback, FLAC__StreamDecoderSeekCallback,
  161. FLAC__StreamDecoderTellCallback, FLAC__StreamDecoderLengthCallback,
  162. FLAC__StreamDecoderEofCallback, FLAC__StreamDecoderWriteCallback,
  163. FLAC__StreamDecoderMetadataCallback,
  164. FLAC__StreamDecoderErrorCallback, ]),
  165. 'FLAC__stream_decoder_init_file': (c_int, [ FLAC__StreamDecoder_p,
  166. FLAC__StreamDecoderWriteCallback,
  167. FLAC__StreamDecoderMetadataCallback,
  168. FLAC__StreamDecoderErrorCallback, ]),
  169. 'FLAC__stream_decoder_finish': (c_int, [ FLAC__StreamDecoder_p, ]),
  170. 'FLAC__stream_decoder_flush': (c_int, [ FLAC__StreamDecoder_p, ]),
  171. 'FLAC__stream_decoder_reset': (c_int, [ FLAC__StreamDecoder_p, ]),
  172. 'FLAC__stream_decoder_process_single': (c_int,
  173. [ FLAC__StreamDecoder_p, ]),
  174. 'FLAC__stream_decoder_process_until_end_of_metadata': (c_int,
  175. [ FLAC__StreamDecoder_p, ]),
  176. 'FLAC__stream_decoder_process_until_end_of_stream': (c_int,
  177. [ FLAC__StreamDecoder_p, ]),
  178. 'FLAC__stream_decoder_seek_absolute': (c_int,
  179. [ FLAC__StreamDecoder_p, c_uint64, ]),
  180. }
  181. for i in funs:
  182. f = getattr(flaclib, i)
  183. f.restype, f.argtypes = funs[i]
  184. def clientdatawrapper(fun):
  185. def newfun(*args):
  186. #print 'nf:', `args`
  187. return fun(*args[1:-1])
  188. return newfun
  189. class FLACDec(object):
  190. channels = property(lambda x: x._channels)
  191. samplerate = property(lambda x: x._samplerate)
  192. bitspersample = property(lambda x: x._bitspersample)
  193. totalsamples = property(lambda x: x._totalsamples)
  194. bytespersample = property(lambda x: x._bytespersample)
  195. def __len__(self):
  196. return self._total_samps
  197. def __init__(self, file):
  198. self.flacdec = None
  199. self._lasterror = None
  200. self.flacdec = flaclib.FLAC__stream_decoder_new()
  201. if self.flacdec == 0:
  202. raise RuntimeError('allocating decoded')
  203. # We need to keep references to the callback functions
  204. # around so they won't be garbage collected.
  205. self.write_wrap = FLAC__StreamDecoderWriteCallback(
  206. clientdatawrapper(self.cb_write))
  207. self.metadata_wrap = FLAC__StreamDecoderMetadataCallback(
  208. clientdatawrapper(self.cb_metadata))
  209. self.error_wrap = FLAC__StreamDecoderErrorCallback(
  210. clientdatawrapper(self.cb_error))
  211. flaclib.FLAC__stream_decoder_set_md5_checking(self.flacdec,
  212. True)
  213. status = flaclib.FLAC__stream_decoder_init_file(self.flacdec,
  214. file, self.write_wrap, self.metadata_wrap,
  215. self.error_wrap, None)
  216. if status != FLAC__STREAM_DECODER_INIT_STATUS_OK:
  217. raise ValueError(
  218. FLAC__StreamDecoderInitStatusString[status])
  219. print 'init'
  220. flaclib.FLAC__stream_decoder_process_until_end_of_metadata(self.flacdec)
  221. print 'end of meta'
  222. if self._lasterror is not None:
  223. raise ValueError(
  224. FLAC__StreamDecoderErrorStatusString[
  225. self._lasterror])
  226. self.curcnt = 0
  227. self.cursamp = 0
  228. def close(self):
  229. if self.flacdec is None:
  230. return
  231. print 'delete called'
  232. if not flaclib.FLAC__stream_decoder_finish(self.flacdec):
  233. md5invalid = True
  234. else:
  235. md5invalid = False
  236. flaclib.FLAC__stream_decoder_delete(self.flacdec)
  237. self.flacdec = None
  238. self.write_wrap = None
  239. self.metadata_wrap = None
  240. self.error_wrap = None
  241. if md5invalid:
  242. pass
  243. #raise ValueError('invalid md5')
  244. def cb_write(self, frame_p, buffer_pp):
  245. frame = frame_p[0]
  246. #print 'write:', `frame`
  247. #for i in xrange(frame.header.channels):
  248. # print '%d:' % i, `frame.subframes[i]`
  249. nchan = frame.header.channels
  250. #print 'sample number:', frame.header.number.sample_number
  251. if frame.header.bits_per_sample == 16:
  252. self.cursamp = frame.header.number.sample_number
  253. self.curcnt = frame.header.blocksize
  254. self.curdata = array.array('h',
  255. [ buffer_pp[x % nchan][x / nchan] for x in
  256. xrange(frame.header.blocksize * nchan)])
  257. if is_little_endian:
  258. self.curdata.byteswap()
  259. else:
  260. print 'ERROR!'
  261. return 0
  262. def cb_metadata(self, metadata_p):
  263. md = metadata_p[0]
  264. print 'metadata:', `md`
  265. if md.type == 0:
  266. si = md.data.stream_info
  267. self._channels = si.channels
  268. self._samplerate = si.sample_rate
  269. self._bitspersample = si.bits_per_sample
  270. self._totalsamples = si.total_samples
  271. self._bytespersample = si.channels * si.bits_per_sample / 8
  272. print `si`
  273. def cb_error(self, errstatus):
  274. self._lasterror = errstatus
  275. def goto(self, pos):
  276. if self.flacdec is None:
  277. raise ValueError('closed')
  278. pos = min(self.totalsamples, pos)
  279. if flaclib.FLAC__stream_decoder_seek_absolute(self.flacdec, pos):
  280. return
  281. # the slow way
  282. if self.cursamp > pos:
  283. if not flaclib.FLAC__stream_decoder_reset(self.flacdec):
  284. raise RuntimeError('unable to seek to beginin')
  285. flaclib.FLAC__stream_decoder_process_until_end_of_metadata(self.flacdec)
  286. flaclib.FLAC__stream_decoder_process_single(self.flacdec)
  287. read = pos - self.cursamp
  288. while read:
  289. tread = min(read, 512*1024)
  290. self.read(tread)
  291. read -= tread
  292. def read(self, nsamp):
  293. if self.flacdec is None:
  294. raise ValueError('closed')
  295. r = []
  296. nsamp = min(nsamp, self.totalsamples - self.cursamp)
  297. while nsamp:
  298. cnt = min(nsamp, self.curcnt)
  299. sampcnt = cnt * self.channels
  300. if cnt == 0 and self.curcnt == 0:
  301. flaclib.FLAC__stream_decoder_process_single(self.flacdec)
  302. continue
  303. r.append(self.curdata[:sampcnt].tostring())
  304. self.cursamp += cnt
  305. self.curcnt -= cnt
  306. self.curdata = self.curdata[sampcnt:]
  307. nsamp -= cnt
  308. return ''.join(r)
  309. if __name__ == '__main__':
  310. import sys
  311. d = FLACDec(sys.argv[1])
  312. print 'total samples:', d.totalsamples
  313. print 'channels:', d.channels
  314. print 'rate:', d.samplerate
  315. print 'bps:', d.bitspersample
  316. print `d.read(10)`
  317. print 'going'
  318. d.goto(d.totalsamples - 128)
  319. print 'here'
  320. print `d.read(10)`