helix-aac.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /*
  2. * Squeezelite - lightweight headless squeezebox emulator
  3. *
  4. * (c) Adrian Smith 2012-2015, triode1@btinternet.com
  5. * Ralph Irving 2015-2017, ralph_irving@hotmail.com
  6. * Philippe, philippe_44@outlook.com
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #include "squeezelite.h"
  23. #include <aacdec.h>
  24. // AAC_MAX_SAMPLES is the number of samples for one channel
  25. #define FRAME_BUF (AAC_MAX_NSAMPS*2)
  26. #if BYTES_PER_FRAME == 4
  27. #define ALIGN(n) (n)
  28. #else
  29. #define ALIGN(n) (n << 16)
  30. #endif
  31. #define WRAPBUF_LEN 2048
  32. static unsigned rates[] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 };
  33. struct chunk_table {
  34. u32_t sample, offset;
  35. };
  36. struct helixaac {
  37. HAACDecoder hAac;
  38. u8_t type;
  39. u8_t *write_buf;
  40. u8_t *wrap_buf;
  41. // following used for mp4 only
  42. u32_t consume;
  43. u32_t pos;
  44. u32_t sample;
  45. u32_t nextchunk;
  46. void *stsc;
  47. u32_t skip;
  48. u64_t samples;
  49. u64_t sttssamples;
  50. bool empty;
  51. struct chunk_table *chunkinfo;
  52. #if !LINKALL
  53. #endif
  54. };
  55. static struct helixaac *a;
  56. extern log_level loglevel;
  57. extern struct buffer *streambuf;
  58. extern struct buffer *outputbuf;
  59. extern struct streamstate stream;
  60. extern struct outputstate output;
  61. extern struct decodestate decode;
  62. extern struct processstate process;
  63. #define LOCK_S mutex_lock(streambuf->mutex)
  64. #define UNLOCK_S mutex_unlock(streambuf->mutex)
  65. #define LOCK_O mutex_lock(outputbuf->mutex)
  66. #define UNLOCK_O mutex_unlock(outputbuf->mutex)
  67. #if PROCESS
  68. #define LOCK_O_direct if (decode.direct) mutex_lock(outputbuf->mutex)
  69. #define UNLOCK_O_direct if (decode.direct) mutex_unlock(outputbuf->mutex)
  70. #define IF_DIRECT(x) if (decode.direct) { x }
  71. #define IF_PROCESS(x) if (!decode.direct) { x }
  72. #else
  73. #define LOCK_O_direct mutex_lock(outputbuf->mutex)
  74. #define UNLOCK_O_direct mutex_unlock(outputbuf->mutex)
  75. #define IF_DIRECT(x) { x }
  76. #define IF_PROCESS(x)
  77. #endif
  78. #if LINKALL
  79. #define HAAC(h, fn, ...) (AAC ## fn)(__VA_ARGS__)
  80. #else
  81. #define HAAC(h, fn, ...) (h)->AAC##fn(__VA_ARGS__)
  82. #endif
  83. // minimal code for mp4 file parsing to extract audio config and find media data
  84. // adapted from faad2/common/mp4ff
  85. u32_t mp4_desc_length(u8_t **buf) {
  86. u8_t b;
  87. u8_t num_bytes = 0;
  88. u32_t length = 0;
  89. do {
  90. b = **buf;
  91. *buf += 1;
  92. num_bytes++;
  93. length = (length << 7) | (b & 0x7f);
  94. } while ((b & 0x80) && num_bytes < 4);
  95. return length;
  96. }
  97. // read mp4 header to extract config data
  98. static int read_mp4_header(unsigned long *samplerate_p, unsigned char *channels_p) {
  99. size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
  100. char type[5];
  101. u32_t len;
  102. while (bytes >= 8) {
  103. // count trak to find the first playable one
  104. static unsigned trak, play;
  105. u32_t consume;
  106. len = unpackN((u32_t *)streambuf->readp);
  107. memcpy(type, streambuf->readp + 4, 4);
  108. type[4] = '\0';
  109. if (!strcmp(type, "moov")) {
  110. trak = 0;
  111. play = 0;
  112. }
  113. if (!strcmp(type, "trak")) {
  114. trak++;
  115. }
  116. // extract audio config from within esds and pass to DecInit2
  117. if (!strcmp(type, "esds") && bytes > len) {
  118. u8_t *ptr = streambuf->readp + 12;
  119. AACFrameInfo info;
  120. if (*ptr++ == 0x03) {
  121. mp4_desc_length(&ptr);
  122. ptr += 4;
  123. } else {
  124. ptr += 3;
  125. }
  126. mp4_desc_length(&ptr);
  127. ptr += 13;
  128. if (*ptr++ != 0x05) {
  129. LOG_WARN("error parsing esds");
  130. return -1;
  131. }
  132. int desc_len = mp4_desc_length(&ptr);
  133. int AOT = *ptr >> 3;
  134. info.profile = AAC_PROFILE_LC;
  135. info.sampRateCore = (*ptr++ & 0x07) << 1;
  136. info.sampRateCore |= (*ptr >> 7) & 0x01;
  137. info.sampRateCore = rates[info.sampRateCore];
  138. info.nChans = (*ptr & 0x7f) >> 3;
  139. *channels_p = info.nChans;
  140. // Note that 24 bits frequencies are not handled
  141. #if AAC_ENABLE_SBR
  142. if (AOT == 5 || AOT == 29) {
  143. *samplerate_p = rates[((ptr[0] & 0x03) << 1) | (ptr[1] >> 7)];
  144. LOG_WARN("AAC stream with SBR => high CPU required (use LMS proxied mode)");
  145. } else if (desc_len > 2 && ((ptr[1] << 3) | (ptr[2] >> 5)) == 0x2b7 && (ptr[2] & 0x1f) == 0x05 && (ptr[3] & 0x80)) {
  146. *samplerate_p = rates[(ptr[3] & 0x78) >> 3];
  147. LOG_WARN("AAC stream with extended SBR => high CPU required (use LMS proxied mode)");
  148. } else if (AOT == 2) {
  149. *samplerate_p = info.sampRateCore;
  150. } else {
  151. *samplerate_p = 44100;
  152. LOG_ERROR("AAC audio object type %d not handled", AOT);
  153. }
  154. #else
  155. *samplerate_p = info.sampRateCore;
  156. #endif
  157. HAAC(a, SetRawBlockParams, a->hAac, 0, &info);
  158. LOG_DEBUG("playable aac track: %u (p:%x, r:%d, c:%d, desc_len:%d)", trak, AOT, info.sampRateCore, info.nChans, desc_len);
  159. play = trak;
  160. }
  161. // extract the total number of samples from stts
  162. if (!strcmp(type, "stts") && bytes > len) {
  163. u32_t i;
  164. u8_t *ptr = streambuf->readp + 12;
  165. u32_t entries = unpackN((u32_t *)ptr);
  166. ptr += 4;
  167. for (i = 0; i < entries; ++i) {
  168. u32_t count = unpackN((u32_t *)ptr);
  169. u32_t size = unpackN((u32_t *)(ptr + 4));
  170. a->sttssamples += count * size;
  171. ptr += 8;
  172. }
  173. LOG_DEBUG("total number of samples contained in stts: " FMT_u64, a->sttssamples);
  174. }
  175. // stash sample to chunk info, assume it comes before stco
  176. if (!strcmp(type, "stsc") && bytes > len && !a->chunkinfo) {
  177. a->stsc = malloc(len - 12);
  178. if (a->stsc == NULL) {
  179. LOG_WARN("malloc fail");
  180. return -1;
  181. }
  182. memcpy(a->stsc, streambuf->readp + 12, len - 12);
  183. }
  184. // build offsets table from stco and stored stsc
  185. if (!strcmp(type, "stco") && bytes > len && play == trak) {
  186. u32_t i;
  187. // extract chunk offsets
  188. u8_t *ptr = streambuf->readp + 12;
  189. u32_t entries = unpackN((u32_t *)ptr);
  190. ptr += 4;
  191. a->chunkinfo = malloc(sizeof(struct chunk_table) * (entries + 1));
  192. if (a->chunkinfo == NULL) {
  193. LOG_WARN("malloc fail");
  194. return -1;
  195. }
  196. for (i = 0; i < entries; ++i) {
  197. a->chunkinfo[i].offset = unpackN((u32_t *)ptr);
  198. a->chunkinfo[i].sample = 0;
  199. ptr += 4;
  200. }
  201. a->chunkinfo[i].sample = 0;
  202. a->chunkinfo[i].offset = 0;
  203. // fill in first sample id for each chunk from stored stsc
  204. if (a->stsc) {
  205. u32_t stsc_entries = unpackN((u32_t *)a->stsc);
  206. u32_t sample = 0;
  207. u32_t last = 0, last_samples = 0;
  208. u8_t *ptr = (u8_t *)a->stsc + 4;
  209. while (stsc_entries--) {
  210. u32_t first = unpackN((u32_t *)ptr);
  211. u32_t samples = unpackN((u32_t *)(ptr + 4));
  212. if (last) {
  213. for (i = last - 1; i < first - 1; ++i) {
  214. a->chunkinfo[i].sample = sample;
  215. sample += last_samples;
  216. }
  217. }
  218. if (stsc_entries == 0) {
  219. for (i = first - 1; i < entries; ++i) {
  220. a->chunkinfo[i].sample = sample;
  221. sample += samples;
  222. }
  223. }
  224. last = first;
  225. last_samples = samples;
  226. ptr += 12;
  227. }
  228. free(a->stsc);
  229. a->stsc = NULL;
  230. }
  231. }
  232. // found media data, advance to start of first chunk and return
  233. if (!strcmp(type, "mdat")) {
  234. _buf_inc_readp(streambuf, 8);
  235. a->pos += 8;
  236. bytes -= 8;
  237. if (play) {
  238. LOG_DEBUG("type: mdat len: %u pos: %u", len, a->pos);
  239. if (a->chunkinfo && a->chunkinfo[0].offset > a->pos) {
  240. u32_t skip = a->chunkinfo[0].offset - a->pos;
  241. LOG_DEBUG("skipping: %u", skip);
  242. if (skip <= bytes) {
  243. _buf_inc_readp(streambuf, skip);
  244. a->pos += skip;
  245. } else {
  246. a->consume = skip;
  247. }
  248. }
  249. a->sample = a->nextchunk = 1;
  250. return 1;
  251. } else {
  252. LOG_DEBUG("type: mdat len: %u, no playable track found", len);
  253. return -1;
  254. }
  255. }
  256. // parse key-value atoms within ilst ---- entries to get encoder padding within iTunSMPB entry for gapless
  257. if (!strcmp(type, "----") && bytes > len) {
  258. u8_t *ptr = streambuf->readp + 8;
  259. u32_t remain = len - 8, size;
  260. if (!memcmp(ptr + 4, "mean", 4) && (size = unpackN((u32_t *)ptr)) < remain) {
  261. ptr += size; remain -= size;
  262. }
  263. if (!memcmp(ptr + 4, "name", 4) && (size = unpackN((u32_t *)ptr)) < remain && !memcmp(ptr + 12, "iTunSMPB", 8)) {
  264. ptr += size; remain -= size;
  265. }
  266. if (!memcmp(ptr + 4, "data", 4) && remain > 16 + 48) {
  267. // data is stored as hex strings: 0 start end samples
  268. u32_t b, c; u64_t d;
  269. if (sscanf((const char *)(ptr + 16), "%x %x %x " FMT_x64, &b, &b, &c, &d) == 4) {
  270. LOG_DEBUG("iTunSMPB start: %u end: %u samples: " FMT_u64, b, c, d);
  271. if (a->sttssamples && a->sttssamples < b + c + d) {
  272. LOG_DEBUG("reducing samples as stts count is less");
  273. d = a->sttssamples - (b + c);
  274. }
  275. a->skip = b;
  276. a->samples = d;
  277. }
  278. }
  279. }
  280. // default to consuming entire box
  281. consume = len;
  282. // read into these boxes so reduce consume
  283. if (!strcmp(type, "moov") || !strcmp(type, "trak") || !strcmp(type, "mdia") || !strcmp(type, "minf") || !strcmp(type, "stbl") ||
  284. !strcmp(type, "udta") || !strcmp(type, "ilst")) {
  285. consume = 8;
  286. }
  287. // special cases which mix mix data in the enclosing box which we want to read into
  288. if (!strcmp(type, "stsd")) consume = 16;
  289. if (!strcmp(type, "mp4a")) consume = 36;
  290. if (!strcmp(type, "meta")) consume = 12;
  291. // consume rest of box if it has been parsed (all in the buffer) or is not one we want to parse
  292. if (bytes >= consume) {
  293. LOG_DEBUG("type: %s len: %u consume: %u", type, len, consume);
  294. _buf_inc_readp(streambuf, consume);
  295. a->pos += consume;
  296. bytes -= consume;
  297. } else if ( !(!strcmp(type, "esds") || !strcmp(type, "stts") || !strcmp(type, "stsc") ||
  298. !strcmp(type, "stco") || !strcmp(type, "----")) ) {
  299. LOG_DEBUG("type: %s len: %u consume: %u - partial consume: %u", type, len, consume, bytes);
  300. _buf_inc_readp(streambuf, bytes);
  301. a->pos += bytes;
  302. a->consume = consume - bytes;
  303. break;
  304. } else if (len > streambuf->size) {
  305. // can't process an atom larger than streambuf!
  306. LOG_ERROR("atom %s too large for buffer %u %u", type, len, streambuf->size);
  307. return -1;
  308. } else {
  309. // make sure there is 'len' contiguous space
  310. _buf_unwrap(streambuf, len);
  311. break;
  312. }
  313. }
  314. return 0;
  315. }
  316. static decode_state helixaac_decode(void) {
  317. size_t bytes_total, bytes_wrap;
  318. int res, bytes;
  319. static AACFrameInfo info;
  320. s16_t *iptr;
  321. u8_t *sptr;
  322. bool endstream;
  323. frames_t frames;
  324. LOCK_S;
  325. bytes_total = _buf_used(streambuf);
  326. bytes_wrap = min(bytes_total, _buf_cont_read(streambuf));
  327. if (stream.state <= DISCONNECT && !bytes_total) {
  328. UNLOCK_S;
  329. return DECODE_COMPLETE;
  330. }
  331. if (a->consume) {
  332. u32_t consume = min(a->consume, bytes_wrap);
  333. LOG_DEBUG("consume: %u of %u", consume, a->consume);
  334. _buf_inc_readp(streambuf, consume);
  335. a->pos += consume;
  336. a->consume -= consume;
  337. UNLOCK_S;
  338. return DECODE_RUNNING;
  339. }
  340. if (decode.new_stream) {
  341. int found = 0;
  342. static unsigned char channels;
  343. static unsigned long samplerate;
  344. if (a->type == '2') {
  345. // adts stream - seek for header
  346. long n = HAAC(a, FindSyncWord, streambuf->readp, bytes_wrap);
  347. LOG_DEBUG("Sync search in %d bytes %d", bytes_wrap, n);
  348. if (n >= 0) {
  349. u8_t *p = streambuf->readp + n;
  350. int bytes = bytes_wrap - n;
  351. if (!HAAC(a, Decode, a->hAac, &p, &bytes, (s16_t*) a->write_buf)) {
  352. HAAC(a, GetLastFrameInfo, a->hAac, &info);
  353. channels = info.nChans;
  354. samplerate = info.sampRateOut;
  355. found = 1;
  356. } else if (n == 0) n++;
  357. HAAC(a, FlushCodec, a->hAac);
  358. bytes_total -= n;
  359. bytes_wrap -= n;
  360. _buf_inc_readp(streambuf, n);
  361. } else {
  362. found = -1;
  363. }
  364. } else {
  365. // mp4 - read header
  366. found = read_mp4_header(&samplerate, &channels);
  367. }
  368. if (found == 1) {
  369. LOCK_O;
  370. output.next_sample_rate = decode_newstream(samplerate, output.supported_rates);
  371. IF_DSD( output.next_fmt = PCM; )
  372. output.track_start = outputbuf->writep;
  373. if (output.fade_mode) _checkfade(true);
  374. decode.new_stream = false;
  375. UNLOCK_O;
  376. LOG_INFO("setting track start, samplerate: %u channels: %u", samplerate, channels);
  377. bytes_total = _buf_used(streambuf);
  378. bytes_wrap = min(bytes_total, _buf_cont_read(streambuf));
  379. // come back later if we don' thave enough data
  380. if (bytes_total < WRAPBUF_LEN) {
  381. UNLOCK_S;
  382. LOG_INFO("need more audio data");
  383. return DECODE_RUNNING;
  384. }
  385. } else if (found == -1) {
  386. LOG_WARN("error reading stream header");
  387. UNLOCK_S;
  388. return DECODE_ERROR;
  389. } else {
  390. // not finished header parsing come back next time
  391. UNLOCK_S;
  392. LOG_DEBUG("header not found yet");
  393. return DECODE_RUNNING;
  394. }
  395. }
  396. // we always have at least WRAPBUF_LEN unless it's the end of a stream
  397. if (bytes_wrap < WRAPBUF_LEN && bytes_wrap != bytes_total) {
  398. // build a linear buffer if we are crossing the end of streambuf
  399. memcpy(a->wrap_buf, streambuf->readp, bytes_wrap);
  400. memcpy(a->wrap_buf + bytes_wrap, streambuf->buf, min(WRAPBUF_LEN, bytes_total) - bytes_wrap);
  401. sptr = a->wrap_buf;
  402. bytes = bytes_wrap = min(WRAPBUF_LEN, bytes_total);
  403. } else {
  404. sptr = streambuf->readp;
  405. bytes = bytes_wrap;
  406. }
  407. // decode function changes iptr, so can't use streambuf->readp (same for bytes)
  408. res = HAAC(a, Decode, a->hAac, &sptr, &bytes, (s16_t*) a->write_buf);
  409. if (res < 0) {
  410. LOG_WARN("AAC decode error %d", res);
  411. }
  412. HAAC(a, GetLastFrameInfo, a->hAac, &info);
  413. iptr = (s16_t*) a->write_buf;
  414. bytes = bytes_wrap - bytes;
  415. endstream = false;
  416. if (a->chunkinfo && a->chunkinfo[a->nextchunk].offset && a->sample++ == a->chunkinfo[a->nextchunk].sample) {
  417. // mp4 end of chunk - skip to next offset
  418. if (a->chunkinfo[a->nextchunk].offset > a->pos) {
  419. u32_t skip = a->chunkinfo[a->nextchunk].offset - a->pos;
  420. if (skip != bytes) {
  421. LOG_DEBUG("skipping to next chunk pos: %u consumed: %u != skip: %u", a->pos, bytes, skip);
  422. }
  423. if (bytes_total >= skip) {
  424. _buf_inc_readp(streambuf, skip);
  425. a->pos += skip;
  426. } else {
  427. a->consume = skip;
  428. }
  429. a->nextchunk++;
  430. } else {
  431. LOG_ERROR("error: need to skip backwards!");
  432. endstream = true;
  433. }
  434. } else if (bytes > 0) {
  435. // adts and mp4 when not at end of chunk
  436. _buf_inc_readp(streambuf, bytes);
  437. a->pos += bytes;
  438. } else {
  439. // error which doesn't advance streambuf - end
  440. endstream = true;
  441. }
  442. UNLOCK_S;
  443. if (endstream) {
  444. LOG_WARN("unable to decode further");
  445. return DECODE_ERROR;
  446. }
  447. if (!info.outputSamps) {
  448. a->empty = true;
  449. return DECODE_RUNNING;
  450. }
  451. frames = info.outputSamps / info.nChans;
  452. if (a->skip) {
  453. u32_t skip;
  454. if (a->empty) {
  455. a->empty = false;
  456. a->skip -= frames;
  457. LOG_DEBUG("gapless: first frame empty, skipped %u frames at start", frames);
  458. }
  459. skip = min(frames, a->skip);
  460. LOG_DEBUG("gapless: skipping %u frames at start", skip);
  461. frames -= skip;
  462. a->skip -= skip;
  463. iptr += skip * info.nChans;
  464. }
  465. if (a->samples) {
  466. if (a->samples < frames) {
  467. LOG_DEBUG("gapless: trimming %u frames from end", frames - a->samples);
  468. frames = (frames_t)a->samples;
  469. }
  470. a->samples -= frames;
  471. }
  472. LOG_SDEBUG("write %u frames", frames);
  473. LOCK_O_direct;
  474. while (frames > 0) {
  475. frames_t f;
  476. frames_t count;
  477. ISAMPLE_T *optr;
  478. IF_DIRECT(
  479. f = _buf_cont_write(outputbuf) / BYTES_PER_FRAME;
  480. optr = (ISAMPLE_T *)outputbuf->writep;
  481. );
  482. IF_PROCESS(
  483. f = process.max_in_frames;
  484. optr = (ISAMPLE_T *)process.inbuf;
  485. );
  486. f = min(f, frames);
  487. count = f;
  488. if (info.nChans == 2) {
  489. #if BYTES_PER_FRAME == 4
  490. memcpy(optr, iptr, count * BYTES_PER_FRAME);
  491. iptr += count * 2;
  492. #else
  493. while (count--) {
  494. *optr++ = ALIGN(*iptr++);
  495. *optr++ = ALIGN(*iptr++);
  496. }
  497. #endif
  498. } else if (info.nChans == 1) {
  499. while (count--) {
  500. *optr++ = ALIGN(*iptr);
  501. *optr++ = ALIGN(*iptr++);
  502. }
  503. } else {
  504. LOG_WARN("unsupported number of channels");
  505. }
  506. frames -= f;
  507. IF_DIRECT(
  508. _buf_inc_writep(outputbuf, f * BYTES_PER_FRAME);
  509. );
  510. IF_PROCESS(
  511. process.in_frames = f;
  512. if (frames) LOG_ERROR("unhandled case");
  513. );
  514. }
  515. UNLOCK_O_direct;
  516. return DECODE_RUNNING;
  517. }
  518. static void helixaac_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
  519. LOG_INFO("opening %s stream", size == '2' ? "adts" : "mp4");
  520. a->type = size;
  521. a->pos = a->consume = a->sample = a->nextchunk = 0;
  522. if (a->chunkinfo) {
  523. free(a->chunkinfo);
  524. }
  525. if (a->stsc) {
  526. free(a->stsc);
  527. }
  528. a->chunkinfo = NULL;
  529. a->stsc = NULL;
  530. a->skip = 0;
  531. a->samples = 0;
  532. a->sttssamples = 0;
  533. a->empty = false;
  534. if (a->hAac) {
  535. // always free decoder as flush only works when no parameter has changed
  536. HAAC(a, FreeDecoder, a->hAac);
  537. } else {
  538. a->write_buf = malloc(FRAME_BUF * 4);
  539. a->wrap_buf = malloc(WRAPBUF_LEN);
  540. }
  541. a->hAac = HAAC(a, InitDecoder);
  542. }
  543. static void helixaac_close(void) {
  544. HAAC(a, FreeDecoder, a->hAac);
  545. a->hAac = NULL;
  546. if (a->chunkinfo) {
  547. free(a->chunkinfo);
  548. a->chunkinfo = NULL;
  549. }
  550. if (a->stsc) {
  551. free(a->stsc);
  552. a->stsc = NULL;
  553. }
  554. free(a->write_buf);
  555. free(a->wrap_buf);
  556. }
  557. static bool load_helixaac() {
  558. #if !LINKALL
  559. void *handle = dlopen(LIBHELIX-AAC, RTLD_NOW);
  560. char *err;
  561. if (!handle) {
  562. LOG_INFO("dlerror: %s", dlerror());
  563. return false;
  564. }
  565. // load symbols here
  566. if ((err = dlerror()) != NULL) {
  567. LOG_INFO("dlerror: %s", err);
  568. return false;
  569. }
  570. LOG_INFO("loaded "LIBHELIX-AAC"");
  571. #endif
  572. return true;
  573. }
  574. struct codec *register_helixaac(void) {
  575. static struct codec ret = {
  576. 'a', // id
  577. "aac", // types
  578. WRAPBUF_LEN, // min read
  579. 20480, // min space
  580. helixaac_open, // open
  581. helixaac_close, // close
  582. helixaac_decode, // decode
  583. };
  584. a = malloc(sizeof(struct helixaac));
  585. if (!a) {
  586. return NULL;
  587. }
  588. a->hAac = NULL;
  589. a->chunkinfo = NULL;
  590. a->stsc = NULL;
  591. if (!load_helixaac()) {
  592. return NULL;
  593. }
  594. LOG_INFO("using helix-aac to decode aac");
  595. return &ret;
  596. }