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.

604 lines
20KB

  1. /*
  2. * Copyright (C) 2007 Marc Hoffman <marc.hoffman@analog.com>
  3. * April 20, 2007
  4. *
  5. * Blackfin Video Color Space Converters Operations
  6. * convert I420 YV12 to RGB in various formats,
  7. *
  8. * This file is part of FFmpeg.
  9. *
  10. * FFmpeg is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation; either
  13. * version 2.1 of the License, or (at your option) any later version.
  14. *
  15. * FFmpeg is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with FFmpeg; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. */
  24. /*
  25. YUV420 to RGB565 conversion. This routine takes a YUV 420 planar macroblock
  26. and converts it to RGB565. R:5 bits, G:6 bits, B:5 bits.. packed into shorts
  27. The following calculation is used for the conversion:
  28. r = clipz((y-oy)*cy + crv*(v-128))
  29. g = clipz((y-oy)*cy + cgv*(v-128) + cgu*(u-128))
  30. b = clipz((y-oy)*cy + cbu*(u-128))
  31. y,u,v are pre scaled by a factor of 4 i.e. left shifted to gain precision.
  32. New factorization to elliminate the truncation error which was
  33. occuring due to the byteop3p.
  34. 1) use the bytop16m to subtract quad bytes we use this in U8 this
  35. then so the offsets need to be renormalized to 8bits.
  36. 2) scale operands up by a factor of 4 not 8 because Blackfin
  37. multiplies include a shift.
  38. 3) compute into the accumulators cy*yx0, cy*yx1
  39. 4) compute each of the linear equations
  40. r = clipz((y-oy)*cy + crv*(v-128))
  41. g = clipz((y-oy)*cy + cgv*(v-128) + cgu*(u-128))
  42. b = clipz((y-oy)*cy + cbu*(u-128))
  43. reuse of the accumulators requires that we actually multiply
  44. twice once with addition and the second time with a subtaction.
  45. because of this we need to compute the equations in the order R B
  46. then G saving the writes for B in the case of 24/32 bit color
  47. formats.
  48. api: yuv2rgb_kind (uint8_t *Y, uint8_t *U, uint8_t *V, int *out,
  49. int dW, uint32_t *coeffs);
  50. A B
  51. --- ---
  52. i2 = cb i3 = cr
  53. i1 = coeff i0 = y
  54. Where coeffs have the following layout in memory.
  55. uint32_t oy,oc,zero,cy,crv,rmask,cbu,bmask,cgu,cgv;
  56. coeffs is a pointer to oy.
  57. the {rgb} masks are only utilized by the 565 packing algorithm. Note the data
  58. replication is used to simplify the internal algorithms for the dual mac architecture
  59. of BlackFin.
  60. All routines are exported with _ff_bfin_ as a symbol prefix
  61. rough performance gain compared against -O3:
  62. 2779809/1484290 187.28%
  63. which translates to ~33c/pel to ~57c/pel for the reference vs 17.5
  64. c/pel for the optimized implementations. Not sure why there is such a
  65. huge variation on the reference codes on Blackfin I guess it must have
  66. to do with the memory system.
  67. */
  68. #define mL1 .l1.text
  69. #define mL3 .text
  70. #define MEM mL1
  71. #define DEFUN(fname,where,interface) \
  72. .section where; \
  73. .global _ff_bfin_ ## fname; \
  74. .type _ff_bfin_ ## fname, STT_FUNC; \
  75. .align 8; \
  76. _ff_bfin_ ## fname
  77. #define DEFUN_END(fname) \
  78. .size _ff_bfin_ ## fname, . - _ff_bfin_ ## fname
  79. .text
  80. #define COEFF_LEN 11*4
  81. #define COEFF_REL_CY_OFF 4*4
  82. #define ARG_OUT 20
  83. #define ARG_W 24
  84. #define ARG_COEFF 28
  85. DEFUN(yuv2rgb565_line,MEM,
  86. (uint8_t *Y, uint8_t *U, uint8_t *V, int *out, int dW, uint32_t *coeffs)):
  87. link 0;
  88. [--sp] = (r7:4);
  89. p1 = [fp+ARG_OUT];
  90. r3 = [fp+ARG_W];
  91. i0 = r0;
  92. i2 = r1;
  93. i3 = r2;
  94. r0 = [fp+ARG_COEFF];
  95. i1 = r0;
  96. b1 = i1;
  97. l1 = COEFF_LEN;
  98. m0 = COEFF_REL_CY_OFF;
  99. p0 = r3;
  100. r0 = [i0++]; // 2Y
  101. r1.l = w[i2++]; // 2u
  102. r1.h = w[i3++]; // 2v
  103. p0 = p0>>2;
  104. lsetup (.L0565, .L1565) lc0 = p0;
  105. /*
  106. uint32_t oy,oc,zero,cy,crv,rmask,cbu,bmask,cgu,cgv
  107. r0 -- used to load 4ys
  108. r1 -- used to load 2us,2vs
  109. r4 -- y3,y2
  110. r5 -- y1,y0
  111. r6 -- u1,u0
  112. r7 -- v1,v0
  113. */
  114. r2=[i1++]; // oy
  115. .L0565:
  116. /*
  117. rrrrrrrr gggggggg bbbbbbbb
  118. 5432109876543210
  119. bbbbb >>3
  120. gggggggg <<3
  121. rrrrrrrr <<8
  122. rrrrrggggggbbbbb
  123. */
  124. (r4,r5) = byteop16m (r1:0, r3:2) || r3=[i1++]; // oc
  125. (r7,r6) = byteop16m (r1:0, r3:2) (r);
  126. r5 = r5 << 2 (v); // y1,y0
  127. r4 = r4 << 2 (v); // y3,y2
  128. r6 = r6 << 2 (v) || r0=[i1++]; // u1,u0, r0=zero
  129. r7 = r7 << 2 (v) || r1=[i1++]; // v1,v0 r1=cy
  130. /* Y' = y*cy */
  131. a1 = r1.h*r5.h, a0 = r1.l*r5.l || r1=[i1++]; // crv
  132. /* R = Y+ crv*(Cr-128) */
  133. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  134. a1 -= r1.h*r7.l, a0 -= r1.l*r7.l || r5=[i1++]; // rmask
  135. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  136. r2 = r2 >> 3 (v);
  137. r3 = r2 & r5;
  138. /* B = Y+ cbu*(Cb-128) */
  139. r2.h = (a1 += r1.h*r6.l), r2.l = (a0 += r1.l*r6.l);
  140. a1 -= r1.h*r6.l, a0 -= r1.l*r6.l || r5=[i1++]; // bmask
  141. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  142. r2 = r2 << 8 (v);
  143. r2 = r2 & r5;
  144. r3 = r3 | r2;
  145. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  146. a1 += r1.h*r6.l, a0 += r1.l*r6.l || r1=[i1++]; // cgv
  147. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  148. r2 = byteop3p(r3:2, r1:0)(LO) || r5=[i1++m0]; // gmask
  149. r2 = r2 << 3 (v);
  150. r2 = r2 & r5;
  151. r3 = r3 | r2;
  152. [p1++]=r3 || r1=[i1++]; // cy
  153. /* Y' = y*cy */
  154. a1 = r1.h*r4.h, a0 = r1.l*r4.l || r1=[i1++]; // crv
  155. /* R = Y+ crv*(Cr-128) */
  156. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h);
  157. a1 -= r1.h*r7.h, a0 -= r1.l*r7.h || r5=[i1++]; // rmask
  158. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  159. r2 = r2 >> 3 (v);
  160. r3 = r2 & r5;
  161. /* B = Y+ cbu*(Cb-128) */
  162. r2.h = (a1 += r1.h*r6.h), r2.l = (a0 += r1.l*r6.h);
  163. a1 -= r1.h*r6.h, a0 -= r1.l*r6.h || r5=[i1++]; // bmask
  164. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  165. r2 = r2 << 8 (v);
  166. r2 = r2 & r5;
  167. r3 = r3 | r2;
  168. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  169. a1 += r1.h*r6.h, a0 += r1.l*r6.h || r1=[i1++]; // cgv
  170. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h) || r5=[i1++]; // gmask
  171. r2 = byteop3p(r3:2, r1:0)(LO) || r0 = [i0++]; // 2Y
  172. r2 = r2 << 3 (v) || r1.l = w[i2++]; // 2u
  173. r2 = r2 & r5;
  174. r3 = r3 | r2;
  175. [p1++]=r3 || r1.h = w[i3++]; // 2v
  176. .L1565: r2=[i1++]; // oy
  177. l1 = 0;
  178. (r7:4) = [sp++];
  179. unlink;
  180. rts;
  181. DEFUN_END(yuv2rgb565_line)
  182. DEFUN(yuv2rgb555_line,MEM,
  183. (uint8_t *Y, uint8_t *U, uint8_t *V, int *out, int dW, uint32_t *coeffs)):
  184. link 0;
  185. [--sp] = (r7:4);
  186. p1 = [fp+ARG_OUT];
  187. r3 = [fp+ARG_W];
  188. i0 = r0;
  189. i2 = r1;
  190. i3 = r2;
  191. r0 = [fp+ARG_COEFF];
  192. i1 = r0;
  193. b1 = i1;
  194. l1 = COEFF_LEN;
  195. m0 = COEFF_REL_CY_OFF;
  196. p0 = r3;
  197. r0 = [i0++]; // 2Y
  198. r1.l = w[i2++]; // 2u
  199. r1.h = w[i3++]; // 2v
  200. p0 = p0>>2;
  201. lsetup (.L0555, .L1555) lc0 = p0;
  202. /*
  203. uint32_t oy,oc,zero,cy,crv,rmask,cbu,bmask,cgu,cgv
  204. r0 -- used to load 4ys
  205. r1 -- used to load 2us,2vs
  206. r4 -- y3,y2
  207. r5 -- y1,y0
  208. r6 -- u1,u0
  209. r7 -- v1,v0
  210. */
  211. r2=[i1++]; // oy
  212. .L0555:
  213. /*
  214. rrrrrrrr gggggggg bbbbbbbb
  215. 5432109876543210
  216. bbbbb >>3
  217. gggggggg <<2
  218. rrrrrrrr <<7
  219. xrrrrrgggggbbbbb
  220. */
  221. (r4,r5) = byteop16m (r1:0, r3:2) || r3=[i1++]; // oc
  222. (r7,r6) = byteop16m (r1:0, r3:2) (r);
  223. r5 = r5 << 2 (v); // y1,y0
  224. r4 = r4 << 2 (v); // y3,y2
  225. r6 = r6 << 2 (v) || r0=[i1++]; // u1,u0, r0=zero
  226. r7 = r7 << 2 (v) || r1=[i1++]; // v1,v0 r1=cy
  227. /* Y' = y*cy */
  228. a1 = r1.h*r5.h, a0 = r1.l*r5.l || r1=[i1++]; // crv
  229. /* R = Y+ crv*(Cr-128) */
  230. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  231. a1 -= r1.h*r7.l, a0 -= r1.l*r7.l || r5=[i1++]; // rmask
  232. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  233. r2 = r2 >> 3 (v);
  234. r3 = r2 & r5;
  235. /* B = Y+ cbu*(Cb-128) */
  236. r2.h = (a1 += r1.h*r6.l), r2.l = (a0 += r1.l*r6.l);
  237. a1 -= r1.h*r6.l, a0 -= r1.l*r6.l || r5=[i1++]; // bmask
  238. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  239. r2 = r2 << 7 (v);
  240. r2 = r2 & r5;
  241. r3 = r3 | r2;
  242. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  243. a1 += r1.h*r6.l, a0 += r1.l*r6.l || r1=[i1++]; // cgv
  244. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  245. r2 = byteop3p(r3:2, r1:0)(LO) || r5=[i1++m0]; // gmask
  246. r2 = r2 << 2 (v);
  247. r2 = r2 & r5;
  248. r3 = r3 | r2;
  249. [p1++]=r3 || r1=[i1++]; // cy
  250. /* Y' = y*cy */
  251. a1 = r1.h*r4.h, a0 = r1.l*r4.l || r1=[i1++]; // crv
  252. /* R = Y+ crv*(Cr-128) */
  253. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h);
  254. a1 -= r1.h*r7.h, a0 -= r1.l*r7.h || r5=[i1++]; // rmask
  255. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  256. r2 = r2 >> 3 (v);
  257. r3 = r2 & r5;
  258. /* B = Y+ cbu*(Cb-128) */
  259. r2.h = (a1 += r1.h*r6.h), r2.l = (a0 += r1.l*r6.h);
  260. a1 -= r1.h*r6.h, a0 -= r1.l*r6.h || r5=[i1++]; // bmask
  261. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  262. r2 = r2 << 7 (v);
  263. r2 = r2 & r5;
  264. r3 = r3 | r2;
  265. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  266. a1 += r1.h*r6.h, a0 += r1.l*r6.h || r1=[i1++]; // cgv
  267. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h) || r5=[i1++]; // gmask
  268. r2 = byteop3p(r3:2, r1:0)(LO) || r0=[i0++]; // 4Y
  269. r2 = r2 << 2 (v) || r1.l=w[i2++]; // 2u
  270. r2 = r2 & r5;
  271. r3 = r3 | r2;
  272. [p1++]=r3 || r1.h=w[i3++]; // 2v
  273. .L1555: r2=[i1++]; // oy
  274. l1 = 0;
  275. (r7:4) = [sp++];
  276. unlink;
  277. rts;
  278. DEFUN_END(yuv2rgb555_line)
  279. DEFUN(yuv2rgb24_line,MEM,
  280. (uint8_t *Y, uint8_t *U, uint8_t *V, int *out, int dW, uint32_t *coeffs)):
  281. link 0;
  282. [--sp] = (r7:4);
  283. p1 = [fp+ARG_OUT];
  284. r3 = [fp+ARG_W];
  285. p2 = p1;
  286. p2 += 3;
  287. i0 = r0;
  288. i2 = r1;
  289. i3 = r2;
  290. r0 = [fp+ARG_COEFF]; // coeff buffer
  291. i1 = r0;
  292. b1 = i1;
  293. l1 = COEFF_LEN;
  294. m0 = COEFF_REL_CY_OFF;
  295. p0 = r3;
  296. r0 = [i0++]; // 2Y
  297. r1.l = w[i2++]; // 2u
  298. r1.h = w[i3++]; // 2v
  299. p0 = p0>>2;
  300. lsetup (.L0888, .L1888) lc0 = p0;
  301. /*
  302. uint32_t oy,oc,zero,cy,crv,rmask,cbu,bmask,cgu,cgv
  303. r0 -- used to load 4ys
  304. r1 -- used to load 2us,2vs
  305. r4 -- y3,y2
  306. r5 -- y1,y0
  307. r6 -- u1,u0
  308. r7 -- v1,v0
  309. */
  310. r2=[i1++]; // oy
  311. .L0888:
  312. (r4,r5) = byteop16m (r1:0, r3:2) || r3=[i1++]; // oc
  313. (r7,r6) = byteop16m (r1:0, r3:2) (r);
  314. r5 = r5 << 2 (v); // y1,y0
  315. r4 = r4 << 2 (v); // y3,y2
  316. r6 = r6 << 2 (v) || r0=[i1++]; // u1,u0, r0=zero
  317. r7 = r7 << 2 (v) || r1=[i1++]; // v1,v0 r1=cy
  318. /* Y' = y*cy */
  319. a1 = r1.h*r5.h, a0 = r1.l*r5.l || r1=[i1++]; // crv
  320. /* R = Y+ crv*(Cr-128) */
  321. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  322. a1 -= r1.h*r7.l, a0 -= r1.l*r7.l || r5=[i1++]; // rmask
  323. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  324. r2=r2>>16 || B[p1++]=r2;
  325. B[p2++]=r2;
  326. /* B = Y+ cbu*(Cb-128) */
  327. r2.h = (a1 += r1.h*r6.l), r2.l = (a0 += r1.l*r6.l);
  328. a1 -= r1.h*r6.l, a0 -= r1.l*r6.l || r5=[i1++]; // bmask
  329. r3 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  330. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  331. a1 += r1.h*r6.l, a0 += r1.l*r6.l || r1=[i1++]; // cgv
  332. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  333. r2 = byteop3p(r3:2, r1:0)(LO) || r5=[i1++m0]; // gmask, oy,cy,zero
  334. r2=r2>>16 || B[p1++]=r2;
  335. B[p2++]=r2;
  336. r3=r3>>16 || B[p1++]=r3;
  337. B[p2++]=r3 || r1=[i1++]; // cy
  338. p1+=3;
  339. p2+=3;
  340. /* Y' = y*cy */
  341. a1 = r1.h*r4.h, a0 = r1.l*r4.l || r1=[i1++]; // crv
  342. /* R = Y+ crv*(Cr-128) */
  343. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h);
  344. a1 -= r1.h*r7.h, a0 -= r1.l*r7.h || r5=[i1++]; // rmask
  345. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  346. r2=r2>>16 || B[p1++]=r2;
  347. B[p2++]=r2;
  348. /* B = Y+ cbu*(Cb-128) */
  349. r2.h = (a1 += r1.h*r6.h), r2.l = (a0 += r1.l*r6.h);
  350. a1 -= r1.h*r6.h, a0 -= r1.l*r6.h || r5=[i1++]; // bmask
  351. r3 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  352. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  353. a1 += r1.h*r6.h, a0 += r1.l*r6.h || r1=[i1++]; // cgv
  354. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h);
  355. r2 = byteop3p(r3:2, r1:0)(LO) || r5=[i1++]; // gmask
  356. r2=r2>>16 || B[p1++]=r2 || r0 = [i0++]; // 4y
  357. B[p2++]=r2 || r1.l = w[i2++]; // 2u
  358. r3=r3>>16 || B[p1++]=r3 || r1.h = w[i3++]; // 2v
  359. B[p2++]=r3 || r2=[i1++]; // oy
  360. p1+=3;
  361. .L1888: p2+=3;
  362. l1 = 0;
  363. (r7:4) = [sp++];
  364. unlink;
  365. rts;
  366. DEFUN_END(yuv2rgb24_line)
  367. #define ARG_vdst 20
  368. #define ARG_width 24
  369. #define ARG_height 28
  370. #define ARG_lumStride 32
  371. #define ARG_chromStride 36
  372. #define ARG_srcStride 40
  373. DEFUN(uyvytoyv12, mL3, (const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
  374. long width, long height,
  375. long lumStride, long chromStride, long srcStride)):
  376. link 0;
  377. [--sp] = (r7:4,p5:4);
  378. p0 = r1; // Y top even
  379. i2 = r2; // *u
  380. r2 = [fp + ARG_vdst];
  381. i3 = r2; // *v
  382. r1 = [fp + ARG_srcStride];
  383. r2 = r0 + r1;
  384. r1 += -8; // i0,i1 is pre read need to correct
  385. m0 = r1;
  386. i0 = r0; // uyvy_T even
  387. i1 = r2; // uyvy_B odd
  388. p2 = [fp + ARG_lumStride];
  389. p1 = p0 + p2; // Y bot odd
  390. p5 = [fp + ARG_width];
  391. p4 = [fp + ARG_height];
  392. r0 = p5;
  393. p4 = p4 >> 1;
  394. p5 = p5 >> 2;
  395. r2 = [fp + ARG_chromStride];
  396. r0 = r0 >> 1;
  397. r2 = r2 - r0;
  398. m1 = r2;
  399. /* I0,I1 - src input line pointers
  400. * p0,p1 - luma output line pointers
  401. * I2 - dstU
  402. * I3 - dstV
  403. */
  404. lsetup (0f, 1f) lc1 = p4; // H/2
  405. 0: r0 = [i0++] || r2 = [i1++];
  406. r1 = [i0++] || r3 = [i1++];
  407. r4 = byteop1p(r1:0, r3:2);
  408. r5 = byteop1p(r1:0, r3:2) (r);
  409. lsetup (2f, 3f) lc0 = p5; // W/4
  410. 2: r0 = r0 >> 8(v);
  411. r1 = r1 >> 8(v);
  412. r2 = r2 >> 8(v);
  413. r3 = r3 >> 8(v);
  414. r0 = bytepack(r0, r1);
  415. r2 = bytepack(r2, r3) || [p0++] = r0; // yyyy
  416. r6 = pack(r5.l, r4.l) || [p1++] = r2; // yyyy
  417. r7 = pack(r5.h, r4.h) || r0 = [i0++] || r2 = [i1++];
  418. r6 = bytepack(r6, r7) || r1 = [i0++] || r3 = [i1++];
  419. r4 = byteop1p(r1:0, r3:2) || w[i2++] = r6.l; // uu
  420. 3: r5 = byteop1p(r1:0, r3:2) (r) || w[i3++] = r6.h; // vv
  421. i0 += m0;
  422. i1 += m0;
  423. i2 += m1;
  424. i3 += m1;
  425. p0 = p0 + p2;
  426. 1: p1 = p1 + p2;
  427. (r7:4,p5:4) = [sp++];
  428. unlink;
  429. rts;
  430. DEFUN_END(uyvytoyv12)
  431. DEFUN(yuyvtoyv12, mL3, (const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
  432. long width, long height,
  433. long lumStride, long chromStride, long srcStride)):
  434. link 0;
  435. [--sp] = (r7:4,p5:4);
  436. p0 = r1; // Y top even
  437. i2 = r2; // *u
  438. r2 = [fp + ARG_vdst];
  439. i3 = r2; // *v
  440. r1 = [fp + ARG_srcStride];
  441. r2 = r0 + r1;
  442. r1 += -8; // i0,i1 is pre read need to correct
  443. m0 = r1;
  444. i0 = r0; // uyvy_T even
  445. i1 = r2; // uyvy_B odd
  446. p2 = [fp + ARG_lumStride];
  447. p1 = p0 + p2; // Y bot odd
  448. p5 = [fp + ARG_width];
  449. p4 = [fp + ARG_height];
  450. r0 = p5;
  451. p4 = p4 >> 1;
  452. p5 = p5 >> 2;
  453. r2 = [fp + ARG_chromStride];
  454. r0 = r0 >> 1;
  455. r2 = r2 - r0;
  456. m1 = r2;
  457. /* I0,I1 - src input line pointers
  458. * p0,p1 - luma output line pointers
  459. * I2 - dstU
  460. * I3 - dstV
  461. */
  462. lsetup (0f, 1f) lc1 = p4; // H/2
  463. 0: r0 = [i0++] || r2 = [i1++];
  464. r1 = [i0++] || r3 = [i1++];
  465. r4 = bytepack(r0, r1);
  466. r5 = bytepack(r2, r3);
  467. lsetup (2f, 3f) lc0 = p5; // W/4
  468. 2: r0 = r0 >> 8(v) || [p0++] = r4; // yyyy-even
  469. r1 = r1 >> 8(v) || [p1++] = r5; // yyyy-odd
  470. r2 = r2 >> 8(v);
  471. r3 = r3 >> 8(v);
  472. r4 = byteop1p(r1:0, r3:2);
  473. r5 = byteop1p(r1:0, r3:2) (r);
  474. r6 = pack(r5.l, r4.l);
  475. r7 = pack(r5.h, r4.h) || r0 = [i0++] || r2 = [i1++];
  476. r6 = bytepack(r6, r7) || r1 = [i0++] || r3 = [i1++];
  477. r4 = bytepack(r0, r1) || w[i2++] = r6.l; // uu
  478. 3: r5 = bytepack(r2, r3) || w[i3++] = r6.h; // vv
  479. i0 += m0;
  480. i1 += m0;
  481. i2 += m1;
  482. i3 += m1;
  483. p0 = p0 + p2;
  484. 1: p1 = p1 + p2;
  485. (r7:4,p5:4) = [sp++];
  486. unlink;
  487. rts;
  488. DEFUN_END(yuyvtoyv12)