wma.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /* wma player test */
  2. #include "libwma/asf.h"
  3. #include "libwma/wmadec.h"
  4. /* The output buffer containing the decoded samples (channels 0 and 1)
  5. BLOCK_MAX_SIZE is 2048 (samples) and MAX_CHANNELS is 2.
  6. */
  7. static uint32_t decoded[BLOCK_MAX_SIZE * MAX_CHANNELS];
  8. /* NOTE: WMADecodeContext is 120152 bytes (on x86) */
  9. static WMADecodeContext wmadec;
  10. enum asf_error_e {
  11. ASF_ERROR_INTERNAL = -1, /* incorrect input to API calls */
  12. ASF_ERROR_OUTOFMEM = -2, /* some malloc inside program failed */
  13. ASF_ERROR_EOF = -3, /* unexpected end of file */
  14. ASF_ERROR_IO = -4, /* error reading or writing to file */
  15. ASF_ERROR_INVALID_LENGTH = -5, /* length value conflict in input data */
  16. ASF_ERROR_INVALID_VALUE = -6, /* other value conflict in input data */
  17. ASF_ERROR_INVALID_OBJECT = -7, /* ASF object missing or in wrong place */
  18. ASF_ERROR_OBJECT_SIZE = -8, /* invalid ASF object size (too small) */
  19. ASF_ERROR_SEEKABLE = -9, /* file not seekable */
  20. ASF_ERROR_SEEK = -10 /* file is seekable but seeking failed */
  21. };
  22. static int asf_read_packet(uint8_t** audiobuf, int* audiobufsize, int* packetlength, asf_waveformatex_t* wfx)
  23. {
  24. uint8_t tmp8, packet_flags, packet_property;
  25. int stream_id;
  26. int ec_length, opaque_data, ec_length_type;
  27. int datalen;
  28. uint8_t data[18];
  29. uint8_t* datap;
  30. uint32_t length;
  31. uint32_t padding_length;
  32. uint32_t send_time;
  33. uint16_t duration;
  34. uint16_t payload_count;
  35. int payload_length_type;
  36. uint32_t payload_hdrlen;
  37. int payload_datalen;
  38. int multiple;
  39. uint32_t replicated_length;
  40. uint32_t media_object_number;
  41. uint32_t media_object_offset;
  42. uint32_t bytesread = 0;
  43. uint8_t* buf;
  44. size_t bufsize;
  45. int i;
  46. /* rt_kprintf("Reading new packet at %d bytes ", (int)ci->curpos); */
  47. if (ci->read_filebuf(&tmp8, 1) == 0)
  48. {
  49. return ASF_ERROR_EOF;
  50. }
  51. bytesread++;
  52. /* TODO: We need a better way to detect endofstream */
  53. if (tmp8 != 0x82)
  54. {
  55. rt_kprintf("Read failed: packet did not sync\n");
  56. return -1;
  57. }
  58. if (tmp8 & 0x80)
  59. {
  60. ec_length = tmp8 & 0x0f;
  61. opaque_data = (tmp8 >> 4) & 0x01;
  62. ec_length_type = (tmp8 >> 5) & 0x03;
  63. if (ec_length_type != 0x00 || opaque_data != 0 || ec_length != 0x02)
  64. {
  65. rt_kprintf("incorrect error correction flags\n");
  66. return ASF_ERROR_INVALID_VALUE;
  67. }
  68. /* Skip ec_data */
  69. ci->advance_buffer(ec_length);
  70. bytesread += ec_length;
  71. }
  72. else
  73. {
  74. ec_length = 0;
  75. }
  76. if (ci->read_filebuf(&packet_flags, 1) == 0)
  77. {
  78. return ASF_ERROR_EOF;
  79. }
  80. if (ci->read_filebuf(&packet_property, 1) == 0)
  81. {
  82. return ASF_ERROR_EOF;
  83. }
  84. bytesread += 2;
  85. datalen = GETLEN2b((packet_flags >> 1) & 0x03) +
  86. GETLEN2b((packet_flags >> 3) & 0x03) +
  87. GETLEN2b((packet_flags >> 5) & 0x03) + 6;
  88. if (ci->read_filebuf(data, datalen) == 0)
  89. {
  90. return ASF_ERROR_EOF;
  91. }
  92. bytesread += datalen;
  93. datap = data;
  94. length = GETVALUE2b((packet_flags >> 5) & 0x03, datap);
  95. datap += GETLEN2b((packet_flags >> 5) & 0x03);
  96. /* sequence value is not used */
  97. GETVALUE2b((packet_flags >> 1) & 0x03, datap);
  98. datap += GETLEN2b((packet_flags >> 1) & 0x03);
  99. padding_length = GETVALUE2b((packet_flags >> 3) & 0x03, datap);
  100. datap += GETLEN2b((packet_flags >> 3) & 0x03);
  101. send_time = get_long_le(datap);
  102. datap += 4;
  103. duration = get_short_le(datap);
  104. datap += 2;
  105. /* rt_kprintf("and duration %d ms\n", duration); */
  106. /* this is really idiotic, packet length can (and often will) be
  107. * undefined and we just have to use the header packet size as the size
  108. * value */
  109. if (!((packet_flags >> 5) & 0x03))
  110. {
  111. length = wfx->packet_size;
  112. }
  113. /* this is also really idiotic, if packet length is smaller than packet
  114. * size, we need to manually add the additional bytes into padding length
  115. */
  116. if (length < wfx->packet_size)
  117. {
  118. padding_length += wfx->packet_size - length;
  119. length = wfx->packet_size;
  120. }
  121. if (length > wfx->packet_size)
  122. {
  123. rt_kprintf("packet with too big length value\n");
  124. return ASF_ERROR_INVALID_LENGTH;
  125. }
  126. /* check if we have multiple payloads */
  127. if (packet_flags & 0x01)
  128. {
  129. if (ci->read_filebuf(&tmp8, 1) == 0)
  130. {
  131. return ASF_ERROR_EOF;
  132. }
  133. payload_count = tmp8 & 0x3f;
  134. payload_length_type = (tmp8 >> 6) & 0x03;
  135. bytesread++;
  136. }
  137. else
  138. {
  139. payload_count = 1;
  140. payload_length_type = 0x02; /* not used */
  141. }
  142. if (length < bytesread)
  143. {
  144. rt_kprintf("header exceeded packet size, invalid file - length=%d, bytesread=%d\n",(int)length,(int)bytesread);
  145. /* FIXME: should this be checked earlier? */
  146. return ASF_ERROR_INVALID_LENGTH;
  147. }
  148. /* We now parse the individual payloads, and move all payloads
  149. belonging to our audio stream to a contiguous block, starting at
  150. the location of the first payload.
  151. */
  152. *audiobuf = NULL;
  153. *audiobufsize = 0;
  154. *packetlength = length - bytesread;
  155. buf = ci->request_buffer(&bufsize, length);
  156. datap = buf;
  157. if (bufsize != length)
  158. {
  159. /* This should only happen with packets larger than 32KB (the
  160. guard buffer size). All the streams I've seen have
  161. relatively small packets less than about 8KB), but I don't
  162. know what is expected.
  163. */
  164. rt_kprintf("Could not read packet (requested %d bytes, received %d), curpos=%d, aborting\n",
  165. (int)length,(int)bufsize,(int)ci->curpos);
  166. return -1;
  167. }
  168. for (i=0; i<payload_count; i++)
  169. {
  170. stream_id = datap[0]&0x7f;
  171. datap++;
  172. bytesread++;
  173. payload_hdrlen = GETLEN2b(packet_property & 0x03) +
  174. GETLEN2b((packet_property >> 2) & 0x03) +
  175. GETLEN2b((packet_property >> 4) & 0x03);
  176. // rt_kprintf("payload_hdrlen = %d\n",payload_hdrlen);
  177. if (payload_hdrlen > sizeof(data))
  178. {
  179. rt_kprintf("Unexpectedly long datalen in data - %d\n",datalen);
  180. return ASF_ERROR_OUTOFMEM;
  181. }
  182. bytesread += payload_hdrlen;
  183. media_object_number = GETVALUE2b((packet_property >> 4) & 0x03, datap);
  184. datap += GETLEN2b((packet_property >> 4) & 0x03);
  185. media_object_offset = GETVALUE2b((packet_property >> 2) & 0x03, datap);
  186. datap += GETLEN2b((packet_property >> 2) & 0x03);
  187. replicated_length = GETVALUE2b(packet_property & 0x03, datap);
  188. datap += GETLEN2b(packet_property & 0x03);
  189. /* TODO: Validate replicated_length */
  190. /* TODO: Is the content of this important for us? */
  191. datap += replicated_length;
  192. bytesread += replicated_length;
  193. multiple = packet_flags & 0x01;
  194. if (multiple)
  195. {
  196. int x;
  197. x = GETLEN2b(payload_length_type);
  198. if (x != 2)
  199. {
  200. /* in multiple payloads datalen should be a word */
  201. return ASF_ERROR_INVALID_VALUE;
  202. }
  203. payload_datalen = GETVALUE2b(payload_length_type, datap);
  204. datap += x;
  205. bytesread += x;
  206. }
  207. else
  208. {
  209. payload_datalen = length - bytesread - padding_length;
  210. }
  211. if (replicated_length==1)
  212. datap++;
  213. if (stream_id == wfx->audiostream)
  214. {
  215. if (*audiobuf == NULL)
  216. {
  217. /* The first payload can stay where it is */
  218. *audiobuf = datap;
  219. *audiobufsize = payload_datalen;
  220. }
  221. else
  222. {
  223. /* The second and subsequent payloads in this packet
  224. that belong to the audio stream need to be moved to be
  225. contiguous with the first payload.
  226. */
  227. memmove(*audiobuf + *audiobufsize, datap, payload_datalen);
  228. *audiobufsize += payload_datalen;
  229. }
  230. }
  231. datap += payload_datalen;
  232. bytesread += payload_datalen;
  233. }
  234. if (*audiobuf != NULL)
  235. return 1;
  236. else
  237. return 0;
  238. }
  239. /* this is the codec entry point */
  240. void wma_run(void)
  241. {
  242. uint32_t elapsedtime;
  243. int retval;
  244. asf_waveformatex_t wfx;
  245. size_t resume_offset;
  246. int i;
  247. int wmares, res;
  248. uint8_t* audiobuf;
  249. int audiobufsize;
  250. int packetlength = 0;
  251. int errcount = 0;
  252. /* Generic codec initialisation */
  253. next_track:
  254. retval = CODEC_OK;
  255. /* Remember the resume position - when the codec is opened, the
  256. playback engine will reset it. */
  257. resume_offset = ci->id3->offset;
  258. restart_track:
  259. if (codec_init())
  260. {
  261. LOGF("WMA: Error initialising codec\n");
  262. retval = CODEC_ERROR;
  263. goto exit;
  264. }
  265. /* Copy the format metadata we've stored in the id3 TOC field. This
  266. saves us from parsing it again here. */
  267. memcpy(&wfx, ci->id3->toc, sizeof(wfx));
  268. if (wma_decode_init(&wmadec,&wfx) < 0)
  269. {
  270. LOGF("WMA: Unsupported or corrupt file\n");
  271. retval = CODEC_ERROR;
  272. goto exit;
  273. }
  274. if (resume_offset > ci->id3->first_frame_offset)
  275. {
  276. /* Get start of current packet */
  277. int packet_offset = (resume_offset - ci->id3->first_frame_offset)
  278. % wfx.packet_size;
  279. ci->seek_buffer(resume_offset - packet_offset);
  280. elapsedtime = get_timestamp(&i);
  281. ci->set_elapsed(elapsedtime);
  282. }
  283. else
  284. {
  285. /* Now advance the file position to the first frame */
  286. ci->seek_buffer(ci->id3->first_frame_offset);
  287. elapsedtime = 0;
  288. }
  289. resume_offset = 0;
  290. /* The main decoding loop */
  291. res = 1;
  292. while (res >= 0)
  293. {
  294. /* Deal with any pending seek requests */
  295. errcount = 0;
  296. new_packet:
  297. res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx);
  298. if (res < 0)
  299. {
  300. /* We'll try to recover from a parse error a certain number of
  301. * times. If we succeed, the error counter will be reset.
  302. */
  303. errcount++;
  304. rt_kprintf("read_packet error %d, errcount %d\n",wmares, errcount);
  305. if (errcount > 5)
  306. {
  307. goto done;
  308. }
  309. else
  310. {
  311. ci->advance_buffer(packetlength);
  312. goto new_packet;
  313. }
  314. }
  315. else if (res > 0)
  316. {
  317. wma_decode_superframe_init(&wmadec, audiobuf, audiobufsize);
  318. for (i=0; i < wmadec.nb_frames; i++)
  319. {
  320. wmares = wma_decode_superframe_frame(&wmadec,
  321. decoded,
  322. audiobuf, audiobufsize);
  323. if (wmares < 0)
  324. {
  325. /* Do the above, but for errors in decode. */
  326. errcount++;
  327. rt_kprintf("WMA decode error %d, errcount %d\n",wmares, errcount);
  328. if (errcount > 5)
  329. {
  330. goto done;
  331. }
  332. else
  333. {
  334. ci->advance_buffer(packetlength);
  335. goto new_packet;
  336. }
  337. }
  338. else if (wmares > 0)
  339. {
  340. ci->pcmbuf_insert(decoded, NULL, wmares);
  341. }
  342. }
  343. }
  344. }
  345. retval = CODEC_OK;
  346. done:
  347. /*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/
  348. return retval;
  349. }
  350. void wma()
  351. {}
  352. FINSH_FUNCTION_EXPORT(wma, wma test)