aacdec_mips.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. /*
  2. * Copyright (c) 2012
  3. * MIPS Technologies, Inc., California.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
  14. * contributors may be used to endorse or promote products derived from
  15. * this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. *
  29. * Authors: Darko Laus (darko@mips.com)
  30. * Djordje Pesut (djordje@mips.com)
  31. * Mirjana Vulin (mvulin@mips.com)
  32. *
  33. * This file is part of FFmpeg.
  34. *
  35. * FFmpeg is free software; you can redistribute it and/or
  36. * modify it under the terms of the GNU Lesser General Public
  37. * License as published by the Free Software Foundation; either
  38. * version 2.1 of the License, or (at your option) any later version.
  39. *
  40. * FFmpeg is distributed in the hope that it will be useful,
  41. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  42. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  43. * Lesser General Public License for more details.
  44. *
  45. * You should have received a copy of the GNU Lesser General Public
  46. * License along with FFmpeg; if not, write to the Free Software
  47. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  48. */
  49. /**
  50. * @file
  51. * Reference: libavcodec/aacdec.c
  52. */
  53. #include "libavutil/attributes.h"
  54. #include "libavcodec/aac.h"
  55. #include "aacdec_mips.h"
  56. #include "libavcodec/aactab.h"
  57. #include "libavcodec/sinewin.h"
  58. #include "libavutil/mips/asmdefs.h"
  59. #if HAVE_INLINE_ASM
  60. #if HAVE_MIPSFPU
  61. static av_always_inline void float_copy(float *dst, const float *src, int count)
  62. {
  63. // Copy 'count' floats from src to dst
  64. const float *loop_end = src + count;
  65. int temp[8];
  66. // count must be a multiple of 8
  67. av_assert2(count % 8 == 0);
  68. // loop unrolled 8 times
  69. __asm__ volatile (
  70. ".set push \n\t"
  71. ".set noreorder \n\t"
  72. "1: \n\t"
  73. "lw %[temp0], 0(%[src]) \n\t"
  74. "lw %[temp1], 4(%[src]) \n\t"
  75. "lw %[temp2], 8(%[src]) \n\t"
  76. "lw %[temp3], 12(%[src]) \n\t"
  77. "lw %[temp4], 16(%[src]) \n\t"
  78. "lw %[temp5], 20(%[src]) \n\t"
  79. "lw %[temp6], 24(%[src]) \n\t"
  80. "lw %[temp7], 28(%[src]) \n\t"
  81. PTR_ADDIU "%[src], %[src], 32 \n\t"
  82. "sw %[temp0], 0(%[dst]) \n\t"
  83. "sw %[temp1], 4(%[dst]) \n\t"
  84. "sw %[temp2], 8(%[dst]) \n\t"
  85. "sw %[temp3], 12(%[dst]) \n\t"
  86. "sw %[temp4], 16(%[dst]) \n\t"
  87. "sw %[temp5], 20(%[dst]) \n\t"
  88. "sw %[temp6], 24(%[dst]) \n\t"
  89. "sw %[temp7], 28(%[dst]) \n\t"
  90. "bne %[src], %[loop_end], 1b \n\t"
  91. PTR_ADDIU "%[dst], %[dst], 32 \n\t"
  92. ".set pop \n\t"
  93. : [temp0]"=&r"(temp[0]), [temp1]"=&r"(temp[1]),
  94. [temp2]"=&r"(temp[2]), [temp3]"=&r"(temp[3]),
  95. [temp4]"=&r"(temp[4]), [temp5]"=&r"(temp[5]),
  96. [temp6]"=&r"(temp[6]), [temp7]"=&r"(temp[7]),
  97. [src]"+r"(src), [dst]"+r"(dst)
  98. : [loop_end]"r"(loop_end)
  99. : "memory"
  100. );
  101. }
  102. static av_always_inline int lcg_random(unsigned previous_val)
  103. {
  104. union { unsigned u; int s; } v = { previous_val * 1664525u + 1013904223 };
  105. return v.s;
  106. }
  107. static void imdct_and_windowing_mips(AACContext *ac, SingleChannelElement *sce)
  108. {
  109. IndividualChannelStream *ics = &sce->ics;
  110. float *in = sce->coeffs;
  111. float *out = sce->ret;
  112. float *saved = sce->saved;
  113. const float *swindow = ics->use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128;
  114. const float *lwindow_prev = ics->use_kb_window[1] ? ff_aac_kbd_long_1024 : ff_sine_1024;
  115. const float *swindow_prev = ics->use_kb_window[1] ? ff_aac_kbd_short_128 : ff_sine_128;
  116. float *buf = ac->buf_mdct;
  117. int i;
  118. if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
  119. for (i = 0; i < 1024; i += 128)
  120. ac->mdct_small.imdct_half(&ac->mdct_small, buf + i, in + i);
  121. } else
  122. ac->mdct.imdct_half(&ac->mdct, buf, in);
  123. /* window overlapping
  124. * NOTE: To simplify the overlapping code, all 'meaningless' short to long
  125. * and long to short transitions are considered to be short to short
  126. * transitions. This leaves just two cases (long to long and short to short)
  127. * with a little special sauce for EIGHT_SHORT_SEQUENCE.
  128. */
  129. if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) &&
  130. (ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) {
  131. ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 512);
  132. } else {
  133. float_copy(out, saved, 448);
  134. if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
  135. {
  136. float wi;
  137. float wj;
  138. int i;
  139. float temp0, temp1, temp2, temp3;
  140. float *dst0 = out + 448 + 0*128;
  141. float *dst1 = dst0 + 64 + 63;
  142. float *dst2 = saved + 63;
  143. float *win0 = (float*)swindow;
  144. float *win1 = win0 + 64 + 63;
  145. float *win0_prev = (float*)swindow_prev;
  146. float *win1_prev = win0_prev + 64 + 63;
  147. float *src0_prev = saved + 448;
  148. float *src1_prev = buf + 0*128 + 63;
  149. float *src0 = buf + 0*128 + 64;
  150. float *src1 = buf + 1*128 + 63;
  151. for(i = 0; i < 64; i++)
  152. {
  153. temp0 = src0_prev[0];
  154. temp1 = src1_prev[0];
  155. wi = *win0_prev;
  156. wj = *win1_prev;
  157. temp2 = src0[0];
  158. temp3 = src1[0];
  159. dst0[0] = temp0 * wj - temp1 * wi;
  160. dst1[0] = temp0 * wi + temp1 * wj;
  161. wi = *win0;
  162. wj = *win1;
  163. temp0 = src0[128];
  164. temp1 = src1[128];
  165. dst0[128] = temp2 * wj - temp3 * wi;
  166. dst1[128] = temp2 * wi + temp3 * wj;
  167. temp2 = src0[256];
  168. temp3 = src1[256];
  169. dst0[256] = temp0 * wj - temp1 * wi;
  170. dst1[256] = temp0 * wi + temp1 * wj;
  171. dst0[384] = temp2 * wj - temp3 * wi;
  172. dst1[384] = temp2 * wi + temp3 * wj;
  173. temp0 = src0[384];
  174. temp1 = src1[384];
  175. dst0[512] = temp0 * wj - temp1 * wi;
  176. dst2[0] = temp0 * wi + temp1 * wj;
  177. src0++;
  178. src1--;
  179. src0_prev++;
  180. src1_prev--;
  181. win0++;
  182. win1--;
  183. win0_prev++;
  184. win1_prev--;
  185. dst0++;
  186. dst1--;
  187. dst2--;
  188. }
  189. }
  190. } else {
  191. ac->fdsp->vector_fmul_window(out + 448, saved + 448, buf, swindow_prev, 64);
  192. float_copy(out + 576, buf + 64, 448);
  193. }
  194. }
  195. // buffer update
  196. if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
  197. ac->fdsp->vector_fmul_window(saved + 64, buf + 4*128 + 64, buf + 5*128, swindow, 64);
  198. ac->fdsp->vector_fmul_window(saved + 192, buf + 5*128 + 64, buf + 6*128, swindow, 64);
  199. ac->fdsp->vector_fmul_window(saved + 320, buf + 6*128 + 64, buf + 7*128, swindow, 64);
  200. float_copy(saved + 448, buf + 7*128 + 64, 64);
  201. } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) {
  202. float_copy(saved, buf + 512, 448);
  203. float_copy(saved + 448, buf + 7*128 + 64, 64);
  204. } else { // LONG_STOP or ONLY_LONG
  205. float_copy(saved, buf + 512, 512);
  206. }
  207. }
  208. static void apply_ltp_mips(AACContext *ac, SingleChannelElement *sce)
  209. {
  210. const LongTermPrediction *ltp = &sce->ics.ltp;
  211. const uint16_t *offsets = sce->ics.swb_offset;
  212. int i, sfb;
  213. int j, k;
  214. if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) {
  215. float *predTime = sce->ret;
  216. float *predFreq = ac->buf_mdct;
  217. float *p_predTime;
  218. int16_t num_samples = 2048;
  219. if (ltp->lag < 1024)
  220. num_samples = ltp->lag + 1024;
  221. j = (2048 - num_samples) >> 2;
  222. k = (2048 - num_samples) & 3;
  223. p_predTime = &predTime[num_samples];
  224. for (i = 0; i < num_samples; i++)
  225. predTime[i] = sce->ltp_state[i + 2048 - ltp->lag] * ltp->coef;
  226. for (i = 0; i < j; i++) {
  227. /* loop unrolled 4 times */
  228. __asm__ volatile (
  229. "sw $0, 0(%[p_predTime]) \n\t"
  230. "sw $0, 4(%[p_predTime]) \n\t"
  231. "sw $0, 8(%[p_predTime]) \n\t"
  232. "sw $0, 12(%[p_predTime]) \n\t"
  233. PTR_ADDIU "%[p_predTime], %[p_predTime], 16 \n\t"
  234. : [p_predTime]"+r"(p_predTime)
  235. :
  236. : "memory"
  237. );
  238. }
  239. for (i = 0; i < k; i++) {
  240. __asm__ volatile (
  241. "sw $0, 0(%[p_predTime]) \n\t"
  242. PTR_ADDIU "%[p_predTime], %[p_predTime], 4 \n\t"
  243. : [p_predTime]"+r"(p_predTime)
  244. :
  245. : "memory"
  246. );
  247. }
  248. ac->windowing_and_mdct_ltp(ac, predFreq, predTime, &sce->ics);
  249. if (sce->tns.present)
  250. ac->apply_tns(predFreq, &sce->tns, &sce->ics, 0);
  251. for (sfb = 0; sfb < FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++)
  252. if (ltp->used[sfb])
  253. for (i = offsets[sfb]; i < offsets[sfb + 1]; i++)
  254. sce->coeffs[i] += predFreq[i];
  255. }
  256. }
  257. static av_always_inline void fmul_and_reverse(float *dst, const float *src0, const float *src1, int count)
  258. {
  259. /* Multiply 'count' floats in src0 by src1 and store the results in dst in reverse */
  260. /* This should be equivalent to a normal fmul, followed by reversing dst */
  261. // count must be a multiple of 4
  262. av_assert2(count % 4 == 0);
  263. // move src0 and src1 to the last element of their arrays
  264. src0 += count - 1;
  265. src1 += count - 1;
  266. for (; count > 0; count -= 4){
  267. float temp[12];
  268. /* loop unrolled 4 times */
  269. __asm__ volatile (
  270. "lwc1 %[temp0], 0(%[ptr2]) \n\t"
  271. "lwc1 %[temp1], -4(%[ptr2]) \n\t"
  272. "lwc1 %[temp2], -8(%[ptr2]) \n\t"
  273. "lwc1 %[temp3], -12(%[ptr2]) \n\t"
  274. "lwc1 %[temp4], 0(%[ptr3]) \n\t"
  275. "lwc1 %[temp5], -4(%[ptr3]) \n\t"
  276. "lwc1 %[temp6], -8(%[ptr3]) \n\t"
  277. "lwc1 %[temp7], -12(%[ptr3]) \n\t"
  278. "mul.s %[temp8], %[temp0], %[temp4] \n\t"
  279. "mul.s %[temp9], %[temp1], %[temp5] \n\t"
  280. "mul.s %[temp10], %[temp2], %[temp6] \n\t"
  281. "mul.s %[temp11], %[temp3], %[temp7] \n\t"
  282. "swc1 %[temp8], 0(%[ptr1]) \n\t"
  283. "swc1 %[temp9], 4(%[ptr1]) \n\t"
  284. "swc1 %[temp10], 8(%[ptr1]) \n\t"
  285. "swc1 %[temp11], 12(%[ptr1]) \n\t"
  286. PTR_ADDIU "%[ptr1], %[ptr1], 16 \n\t"
  287. PTR_ADDIU "%[ptr2], %[ptr2], -16 \n\t"
  288. PTR_ADDIU "%[ptr3], %[ptr3], -16 \n\t"
  289. : [temp0]"=&f"(temp[0]), [temp1]"=&f"(temp[1]),
  290. [temp2]"=&f"(temp[2]), [temp3]"=&f"(temp[3]),
  291. [temp4]"=&f"(temp[4]), [temp5]"=&f"(temp[5]),
  292. [temp6]"=&f"(temp[6]), [temp7]"=&f"(temp[7]),
  293. [temp8]"=&f"(temp[8]), [temp9]"=&f"(temp[9]),
  294. [temp10]"=&f"(temp[10]), [temp11]"=&f"(temp[11]),
  295. [ptr1]"+r"(dst), [ptr2]"+r"(src0), [ptr3]"+r"(src1)
  296. :
  297. : "memory"
  298. );
  299. }
  300. }
  301. static void update_ltp_mips(AACContext *ac, SingleChannelElement *sce)
  302. {
  303. IndividualChannelStream *ics = &sce->ics;
  304. float *saved = sce->saved;
  305. float *saved_ltp = sce->coeffs;
  306. const float *lwindow = ics->use_kb_window[0] ? ff_aac_kbd_long_1024 : ff_sine_1024;
  307. const float *swindow = ics->use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128;
  308. uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
  309. if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
  310. float *p_saved_ltp = saved_ltp + 576;
  311. float *loop_end1 = p_saved_ltp + 448;
  312. float_copy(saved_ltp, saved, 512);
  313. /* loop unrolled 8 times */
  314. __asm__ volatile (
  315. "1: \n\t"
  316. "sw $0, 0(%[p_saved_ltp]) \n\t"
  317. "sw $0, 4(%[p_saved_ltp]) \n\t"
  318. "sw $0, 8(%[p_saved_ltp]) \n\t"
  319. "sw $0, 12(%[p_saved_ltp]) \n\t"
  320. "sw $0, 16(%[p_saved_ltp]) \n\t"
  321. "sw $0, 20(%[p_saved_ltp]) \n\t"
  322. "sw $0, 24(%[p_saved_ltp]) \n\t"
  323. "sw $0, 28(%[p_saved_ltp]) \n\t"
  324. PTR_ADDIU "%[p_saved_ltp],%[p_saved_ltp], 32 \n\t"
  325. "bne %[p_saved_ltp], %[loop_end1], 1b \n\t"
  326. : [p_saved_ltp]"+r"(p_saved_ltp)
  327. : [loop_end1]"r"(loop_end1)
  328. : "memory"
  329. );
  330. ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64);
  331. fmul_and_reverse(saved_ltp + 512, ac->buf_mdct + 960, swindow, 64);
  332. } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) {
  333. float *buff0 = saved;
  334. float *buff1 = saved_ltp;
  335. float *loop_end = saved + 448;
  336. /* loop unrolled 8 times */
  337. __asm__ volatile (
  338. ".set push \n\t"
  339. ".set noreorder \n\t"
  340. "1: \n\t"
  341. "lw %[temp0], 0(%[src]) \n\t"
  342. "lw %[temp1], 4(%[src]) \n\t"
  343. "lw %[temp2], 8(%[src]) \n\t"
  344. "lw %[temp3], 12(%[src]) \n\t"
  345. "lw %[temp4], 16(%[src]) \n\t"
  346. "lw %[temp5], 20(%[src]) \n\t"
  347. "lw %[temp6], 24(%[src]) \n\t"
  348. "lw %[temp7], 28(%[src]) \n\t"
  349. PTR_ADDIU "%[src], %[src], 32 \n\t"
  350. "sw %[temp0], 0(%[dst]) \n\t"
  351. "sw %[temp1], 4(%[dst]) \n\t"
  352. "sw %[temp2], 8(%[dst]) \n\t"
  353. "sw %[temp3], 12(%[dst]) \n\t"
  354. "sw %[temp4], 16(%[dst]) \n\t"
  355. "sw %[temp5], 20(%[dst]) \n\t"
  356. "sw %[temp6], 24(%[dst]) \n\t"
  357. "sw %[temp7], 28(%[dst]) \n\t"
  358. "sw $0, 2304(%[dst]) \n\t"
  359. "sw $0, 2308(%[dst]) \n\t"
  360. "sw $0, 2312(%[dst]) \n\t"
  361. "sw $0, 2316(%[dst]) \n\t"
  362. "sw $0, 2320(%[dst]) \n\t"
  363. "sw $0, 2324(%[dst]) \n\t"
  364. "sw $0, 2328(%[dst]) \n\t"
  365. "sw $0, 2332(%[dst]) \n\t"
  366. "bne %[src], %[loop_end], 1b \n\t"
  367. PTR_ADDIU "%[dst], %[dst], 32 \n\t"
  368. ".set pop \n\t"
  369. : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
  370. [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
  371. [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
  372. [temp6]"=&r"(temp6), [temp7]"=&r"(temp7),
  373. [src]"+r"(buff0), [dst]"+r"(buff1)
  374. : [loop_end]"r"(loop_end)
  375. : "memory"
  376. );
  377. ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64);
  378. fmul_and_reverse(saved_ltp + 512, ac->buf_mdct + 960, swindow, 64);
  379. } else { // LONG_STOP or ONLY_LONG
  380. ac->fdsp->vector_fmul_reverse(saved_ltp, ac->buf_mdct + 512, &lwindow[512], 512);
  381. fmul_and_reverse(saved_ltp + 512, ac->buf_mdct + 512, lwindow, 512);
  382. }
  383. float_copy(sce->ltp_state, sce->ltp_state + 1024, 1024);
  384. float_copy(sce->ltp_state + 1024, sce->ret, 1024);
  385. float_copy(sce->ltp_state + 2048, saved_ltp, 1024);
  386. }
  387. #endif /* HAVE_MIPSFPU */
  388. #endif /* HAVE_INLINE_ASM */
  389. void ff_aacdec_init_mips(AACContext *c)
  390. {
  391. #if HAVE_INLINE_ASM
  392. #if HAVE_MIPSFPU
  393. c->imdct_and_windowing = imdct_and_windowing_mips;
  394. c->apply_ltp = apply_ltp_mips;
  395. c->update_ltp = update_ltp_mips;
  396. #endif /* HAVE_MIPSFPU */
  397. #endif /* HAVE_INLINE_ASM */
  398. }