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.

600 lines
19KB

  1. /*
  2. * Copyright (C) 2007 Marc Hoffman <marc.hoffman@analog.com>
  3. * April 20, 2007
  4. *
  5. * Blackfin video color space converter 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 prescaled by a factor of 4 i.e. left-shifted to gain precision.
  32. New factorization to eliminate the truncation error which was
  33. occurring 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 subtraction.
  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
  59. architecture 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. #include "libavutil/bfin/asm.h"
  69. #define MEM mL1
  70. .text
  71. #define COEFF_LEN 11*4
  72. #define COEFF_REL_CY_OFF 4*4
  73. #define ARG_OUT 20
  74. #define ARG_W 24
  75. #define ARG_COEFF 28
  76. DEFUN(yuv2rgb565_line,MEM,
  77. (uint8_t *Y, uint8_t *U, uint8_t *V, int *out, int dW, uint32_t *coeffs)):
  78. link 0;
  79. [--sp] = (r7:4);
  80. p1 = [fp+ARG_OUT];
  81. r3 = [fp+ARG_W];
  82. i0 = r0;
  83. i2 = r1;
  84. i3 = r2;
  85. r0 = [fp+ARG_COEFF];
  86. i1 = r0;
  87. b1 = i1;
  88. l1 = COEFF_LEN;
  89. m0 = COEFF_REL_CY_OFF;
  90. p0 = r3;
  91. r0 = [i0++]; // 2Y
  92. r1.l = w[i2++]; // 2u
  93. r1.h = w[i3++]; // 2v
  94. p0 = p0>>2;
  95. lsetup (.L0565, .L1565) lc0 = p0;
  96. /*
  97. uint32_t oy,oc,zero,cy,crv,rmask,cbu,bmask,cgu,cgv
  98. r0 -- used to load 4ys
  99. r1 -- used to load 2us,2vs
  100. r4 -- y3,y2
  101. r5 -- y1,y0
  102. r6 -- u1,u0
  103. r7 -- v1,v0
  104. */
  105. r2=[i1++]; // oy
  106. .L0565:
  107. /*
  108. rrrrrrrr gggggggg bbbbbbbb
  109. 5432109876543210
  110. bbbbb >>3
  111. gggggggg <<3
  112. rrrrrrrr <<8
  113. rrrrrggggggbbbbb
  114. */
  115. (r4,r5) = byteop16m (r1:0, r3:2) || r3=[i1++]; // oc
  116. (r7,r6) = byteop16m (r1:0, r3:2) (r);
  117. r5 = r5 << 2 (v); // y1,y0
  118. r4 = r4 << 2 (v); // y3,y2
  119. r6 = r6 << 2 (v) || r0=[i1++]; // u1,u0, r0=zero
  120. r7 = r7 << 2 (v) || r1=[i1++]; // v1,v0 r1=cy
  121. /* Y' = y*cy */
  122. a1 = r1.h*r5.h, a0 = r1.l*r5.l || r1=[i1++]; // crv
  123. /* R = Y+ crv*(Cr-128) */
  124. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  125. a1 -= r1.h*r7.l, a0 -= r1.l*r7.l || r5=[i1++]; // rmask
  126. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  127. r2 = r2 >> 3 (v);
  128. r3 = r2 & r5;
  129. /* B = Y+ cbu*(Cb-128) */
  130. r2.h = (a1 += r1.h*r6.l), r2.l = (a0 += r1.l*r6.l);
  131. a1 -= r1.h*r6.l, a0 -= r1.l*r6.l || r5=[i1++]; // bmask
  132. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  133. r2 = r2 << 8 (v);
  134. r2 = r2 & r5;
  135. r3 = r3 | r2;
  136. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  137. a1 += r1.h*r6.l, a0 += r1.l*r6.l || r1=[i1++]; // cgv
  138. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  139. r2 = byteop3p(r3:2, r1:0)(LO) || r5=[i1++m0]; // gmask
  140. r2 = r2 << 3 (v);
  141. r2 = r2 & r5;
  142. r3 = r3 | r2;
  143. [p1++]=r3 || r1=[i1++]; // cy
  144. /* Y' = y*cy */
  145. a1 = r1.h*r4.h, a0 = r1.l*r4.l || r1=[i1++]; // crv
  146. /* R = Y+ crv*(Cr-128) */
  147. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h);
  148. a1 -= r1.h*r7.h, a0 -= r1.l*r7.h || r5=[i1++]; // rmask
  149. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  150. r2 = r2 >> 3 (v);
  151. r3 = r2 & r5;
  152. /* B = Y+ cbu*(Cb-128) */
  153. r2.h = (a1 += r1.h*r6.h), r2.l = (a0 += r1.l*r6.h);
  154. a1 -= r1.h*r6.h, a0 -= r1.l*r6.h || r5=[i1++]; // bmask
  155. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  156. r2 = r2 << 8 (v);
  157. r2 = r2 & r5;
  158. r3 = r3 | r2;
  159. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  160. a1 += r1.h*r6.h, a0 += r1.l*r6.h || r1=[i1++]; // cgv
  161. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h) || r5=[i1++]; // gmask
  162. r2 = byteop3p(r3:2, r1:0)(LO) || r0 = [i0++]; // 2Y
  163. r2 = r2 << 3 (v) || r1.l = w[i2++]; // 2u
  164. r2 = r2 & r5;
  165. r3 = r3 | r2;
  166. [p1++]=r3 || r1.h = w[i3++]; // 2v
  167. .L1565: r2=[i1++]; // oy
  168. l1 = 0;
  169. (r7:4) = [sp++];
  170. unlink;
  171. rts;
  172. DEFUN_END(yuv2rgb565_line)
  173. DEFUN(yuv2rgb555_line,MEM,
  174. (uint8_t *Y, uint8_t *U, uint8_t *V, int *out, int dW, uint32_t *coeffs)):
  175. link 0;
  176. [--sp] = (r7:4);
  177. p1 = [fp+ARG_OUT];
  178. r3 = [fp+ARG_W];
  179. i0 = r0;
  180. i2 = r1;
  181. i3 = r2;
  182. r0 = [fp+ARG_COEFF];
  183. i1 = r0;
  184. b1 = i1;
  185. l1 = COEFF_LEN;
  186. m0 = COEFF_REL_CY_OFF;
  187. p0 = r3;
  188. r0 = [i0++]; // 2Y
  189. r1.l = w[i2++]; // 2u
  190. r1.h = w[i3++]; // 2v
  191. p0 = p0>>2;
  192. lsetup (.L0555, .L1555) lc0 = p0;
  193. /*
  194. uint32_t oy,oc,zero,cy,crv,rmask,cbu,bmask,cgu,cgv
  195. r0 -- used to load 4ys
  196. r1 -- used to load 2us,2vs
  197. r4 -- y3,y2
  198. r5 -- y1,y0
  199. r6 -- u1,u0
  200. r7 -- v1,v0
  201. */
  202. r2=[i1++]; // oy
  203. .L0555:
  204. /*
  205. rrrrrrrr gggggggg bbbbbbbb
  206. 5432109876543210
  207. bbbbb >>3
  208. gggggggg <<2
  209. rrrrrrrr <<7
  210. xrrrrrgggggbbbbb
  211. */
  212. (r4,r5) = byteop16m (r1:0, r3:2) || r3=[i1++]; // oc
  213. (r7,r6) = byteop16m (r1:0, r3:2) (r);
  214. r5 = r5 << 2 (v); // y1,y0
  215. r4 = r4 << 2 (v); // y3,y2
  216. r6 = r6 << 2 (v) || r0=[i1++]; // u1,u0, r0=zero
  217. r7 = r7 << 2 (v) || r1=[i1++]; // v1,v0 r1=cy
  218. /* Y' = y*cy */
  219. a1 = r1.h*r5.h, a0 = r1.l*r5.l || r1=[i1++]; // crv
  220. /* R = Y+ crv*(Cr-128) */
  221. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  222. a1 -= r1.h*r7.l, a0 -= r1.l*r7.l || r5=[i1++]; // rmask
  223. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  224. r2 = r2 >> 3 (v);
  225. r3 = r2 & r5;
  226. /* B = Y+ cbu*(Cb-128) */
  227. r2.h = (a1 += r1.h*r6.l), r2.l = (a0 += r1.l*r6.l);
  228. a1 -= r1.h*r6.l, a0 -= r1.l*r6.l || r5=[i1++]; // bmask
  229. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  230. r2 = r2 << 7 (v);
  231. r2 = r2 & r5;
  232. r3 = r3 | r2;
  233. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  234. a1 += r1.h*r6.l, a0 += r1.l*r6.l || r1=[i1++]; // cgv
  235. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  236. r2 = byteop3p(r3:2, r1:0)(LO) || r5=[i1++m0]; // gmask
  237. r2 = r2 << 2 (v);
  238. r2 = r2 & r5;
  239. r3 = r3 | r2;
  240. [p1++]=r3 || r1=[i1++]; // cy
  241. /* Y' = y*cy */
  242. a1 = r1.h*r4.h, a0 = r1.l*r4.l || r1=[i1++]; // crv
  243. /* R = Y+ crv*(Cr-128) */
  244. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h);
  245. a1 -= r1.h*r7.h, a0 -= r1.l*r7.h || r5=[i1++]; // rmask
  246. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  247. r2 = r2 >> 3 (v);
  248. r3 = r2 & r5;
  249. /* B = Y+ cbu*(Cb-128) */
  250. r2.h = (a1 += r1.h*r6.h), r2.l = (a0 += r1.l*r6.h);
  251. a1 -= r1.h*r6.h, a0 -= r1.l*r6.h || r5=[i1++]; // bmask
  252. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  253. r2 = r2 << 7 (v);
  254. r2 = r2 & r5;
  255. r3 = r3 | r2;
  256. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  257. a1 += r1.h*r6.h, a0 += r1.l*r6.h || r1=[i1++]; // cgv
  258. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h) || r5=[i1++]; // gmask
  259. r2 = byteop3p(r3:2, r1:0)(LO) || r0=[i0++]; // 4Y
  260. r2 = r2 << 2 (v) || r1.l=w[i2++]; // 2u
  261. r2 = r2 & r5;
  262. r3 = r3 | r2;
  263. [p1++]=r3 || r1.h=w[i3++]; // 2v
  264. .L1555: r2=[i1++]; // oy
  265. l1 = 0;
  266. (r7:4) = [sp++];
  267. unlink;
  268. rts;
  269. DEFUN_END(yuv2rgb555_line)
  270. DEFUN(yuv2rgb24_line,MEM,
  271. (uint8_t *Y, uint8_t *U, uint8_t *V, int *out, int dW, uint32_t *coeffs)):
  272. link 0;
  273. [--sp] = (r7:4);
  274. p1 = [fp+ARG_OUT];
  275. r3 = [fp+ARG_W];
  276. p2 = p1;
  277. p2 += 3;
  278. i0 = r0;
  279. i2 = r1;
  280. i3 = r2;
  281. r0 = [fp+ARG_COEFF]; // coeff buffer
  282. i1 = r0;
  283. b1 = i1;
  284. l1 = COEFF_LEN;
  285. m0 = COEFF_REL_CY_OFF;
  286. p0 = r3;
  287. r0 = [i0++]; // 2Y
  288. r1.l = w[i2++]; // 2u
  289. r1.h = w[i3++]; // 2v
  290. p0 = p0>>2;
  291. lsetup (.L0888, .L1888) lc0 = p0;
  292. /*
  293. uint32_t oy,oc,zero,cy,crv,rmask,cbu,bmask,cgu,cgv
  294. r0 -- used to load 4ys
  295. r1 -- used to load 2us,2vs
  296. r4 -- y3,y2
  297. r5 -- y1,y0
  298. r6 -- u1,u0
  299. r7 -- v1,v0
  300. */
  301. r2=[i1++]; // oy
  302. .L0888:
  303. (r4,r5) = byteop16m (r1:0, r3:2) || r3=[i1++]; // oc
  304. (r7,r6) = byteop16m (r1:0, r3:2) (r);
  305. r5 = r5 << 2 (v); // y1,y0
  306. r4 = r4 << 2 (v); // y3,y2
  307. r6 = r6 << 2 (v) || r0=[i1++]; // u1,u0, r0=zero
  308. r7 = r7 << 2 (v) || r1=[i1++]; // v1,v0 r1=cy
  309. /* Y' = y*cy */
  310. a1 = r1.h*r5.h, a0 = r1.l*r5.l || r1=[i1++]; // crv
  311. /* R = Y+ crv*(Cr-128) */
  312. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  313. a1 -= r1.h*r7.l, a0 -= r1.l*r7.l || r5=[i1++]; // rmask
  314. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  315. r2=r2>>16 || B[p1++]=r2;
  316. B[p2++]=r2;
  317. /* B = Y+ cbu*(Cb-128) */
  318. r2.h = (a1 += r1.h*r6.l), r2.l = (a0 += r1.l*r6.l);
  319. a1 -= r1.h*r6.l, a0 -= r1.l*r6.l || r5=[i1++]; // bmask
  320. r3 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  321. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  322. a1 += r1.h*r6.l, a0 += r1.l*r6.l || r1=[i1++]; // cgv
  323. r2.h = (a1 += r1.h*r7.l), r2.l = (a0 += r1.l*r7.l);
  324. r2 = byteop3p(r3:2, r1:0)(LO) || r5=[i1++m0]; // gmask, oy,cy,zero
  325. r2=r2>>16 || B[p1++]=r2;
  326. B[p2++]=r2;
  327. r3=r3>>16 || B[p1++]=r3;
  328. B[p2++]=r3 || r1=[i1++]; // cy
  329. p1+=3;
  330. p2+=3;
  331. /* Y' = y*cy */
  332. a1 = r1.h*r4.h, a0 = r1.l*r4.l || r1=[i1++]; // crv
  333. /* R = Y+ crv*(Cr-128) */
  334. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h);
  335. a1 -= r1.h*r7.h, a0 -= r1.l*r7.h || r5=[i1++]; // rmask
  336. r2 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cbu
  337. r2=r2>>16 || B[p1++]=r2;
  338. B[p2++]=r2;
  339. /* B = Y+ cbu*(Cb-128) */
  340. r2.h = (a1 += r1.h*r6.h), r2.l = (a0 += r1.l*r6.h);
  341. a1 -= r1.h*r6.h, a0 -= r1.l*r6.h || r5=[i1++]; // bmask
  342. r3 = byteop3p(r3:2, r1:0)(LO) || r1=[i1++]; // cgu
  343. /* G = Y+ cgu*(Cb-128)+cgv*(Cr-128) */
  344. a1 += r1.h*r6.h, a0 += r1.l*r6.h || r1=[i1++]; // cgv
  345. r2.h = (a1 += r1.h*r7.h), r2.l = (a0 += r1.l*r7.h);
  346. r2 = byteop3p(r3:2, r1:0)(LO) || r5=[i1++]; // gmask
  347. r2=r2>>16 || B[p1++]=r2 || r0 = [i0++]; // 4y
  348. B[p2++]=r2 || r1.l = w[i2++]; // 2u
  349. r3=r3>>16 || B[p1++]=r3 || r1.h = w[i3++]; // 2v
  350. B[p2++]=r3 || r2=[i1++]; // oy
  351. p1+=3;
  352. .L1888: p2+=3;
  353. l1 = 0;
  354. (r7:4) = [sp++];
  355. unlink;
  356. rts;
  357. DEFUN_END(yuv2rgb24_line)
  358. #define ARG_vdst 20
  359. #define ARG_width 24
  360. #define ARG_height 28
  361. #define ARG_lumStride 32
  362. #define ARG_chromStride 36
  363. #define ARG_srcStride 40
  364. DEFUN(uyvytoyv12, mL3, (const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
  365. int width, int height,
  366. int lumStride, int chromStride, int srcStride)):
  367. link 0;
  368. [--sp] = (r7:4,p5:4);
  369. p0 = r1; // Y top even
  370. i2 = r2; // *u
  371. r2 = [fp + ARG_vdst];
  372. i3 = r2; // *v
  373. r1 = [fp + ARG_srcStride];
  374. r2 = r0 + r1;
  375. i0 = r0; // uyvy_T even
  376. i1 = r2; // uyvy_B odd
  377. p2 = [fp + ARG_lumStride];
  378. p1 = p0 + p2; // Y bot odd
  379. p5 = [fp + ARG_width];
  380. p4 = [fp + ARG_height];
  381. r0 = p5;
  382. p4 = p4 >> 1;
  383. p5 = p5 >> 2;
  384. r2 = r0 << 1;
  385. r1 = r1 << 1;
  386. r1 = r1 - r2; // srcStride + (srcStride - 2*width)
  387. r1 += -8; // i0,i1 is pre read need to correct
  388. m0 = r1;
  389. r2 = [fp + ARG_chromStride];
  390. r0 = r0 >> 1;
  391. r2 = r2 - r0;
  392. m1 = r2;
  393. /* I0,I1 - src input line pointers
  394. * p0,p1 - luma output line pointers
  395. * I2 - dstU
  396. * I3 - dstV
  397. */
  398. lsetup (0f, 1f) lc1 = p4; // H/2
  399. 0: r0 = [i0++] || r2 = [i1++];
  400. r1 = [i0++] || r3 = [i1++];
  401. r4 = byteop1p(r1:0, r3:2);
  402. r5 = byteop1p(r1:0, r3:2) (r);
  403. lsetup (2f, 3f) lc0 = p5; // W/4
  404. 2: r0 = r0 >> 8(v);
  405. r1 = r1 >> 8(v);
  406. r2 = r2 >> 8(v);
  407. r3 = r3 >> 8(v);
  408. r0 = bytepack(r0, r1);
  409. r2 = bytepack(r2, r3) || [p0++] = r0; // yyyy
  410. r6 = pack(r5.l, r4.l) || [p1++] = r2; // yyyy
  411. r7 = pack(r5.h, r4.h) || r0 = [i0++] || r2 = [i1++];
  412. r6 = bytepack(r6, r7) || r1 = [i0++] || r3 = [i1++];
  413. r4 = byteop1p(r1:0, r3:2) || w[i2++] = r6.l; // uu
  414. 3: r5 = byteop1p(r1:0, r3:2) (r) || w[i3++] = r6.h; // vv
  415. i0 += m0;
  416. i1 += m0;
  417. i2 += m1;
  418. i3 += m1;
  419. p0 = p0 + p2;
  420. 1: p1 = p1 + p2;
  421. (r7:4,p5:4) = [sp++];
  422. unlink;
  423. rts;
  424. DEFUN_END(uyvytoyv12)
  425. DEFUN(yuyvtoyv12, mL3, (const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
  426. int width, int height,
  427. int lumStride, int chromStride, int srcStride)):
  428. link 0;
  429. [--sp] = (r7:4,p5:4);
  430. p0 = r1; // Y top even
  431. i2 = r2; // *u
  432. r2 = [fp + ARG_vdst];
  433. i3 = r2; // *v
  434. r1 = [fp + ARG_srcStride];
  435. r2 = r0 + r1;
  436. i0 = r0; // uyvy_T even
  437. i1 = r2; // uyvy_B odd
  438. p2 = [fp + ARG_lumStride];
  439. p1 = p0 + p2; // Y bot odd
  440. p5 = [fp + ARG_width];
  441. p4 = [fp + ARG_height];
  442. r0 = p5;
  443. p4 = p4 >> 1;
  444. p5 = p5 >> 2;
  445. r2 = r0 << 1;
  446. r1 = r1 << 1;
  447. r1 = r1 - r2; // srcStride + (srcStride - 2*width)
  448. r1 += -8; // i0,i1 is pre read need to correct
  449. m0 = r1;
  450. r2 = [fp + ARG_chromStride];
  451. r0 = r0 >> 1;
  452. r2 = r2 - r0;
  453. m1 = r2;
  454. /* I0,I1 - src input line pointers
  455. * p0,p1 - luma output line pointers
  456. * I2 - dstU
  457. * I3 - dstV
  458. */
  459. lsetup (0f, 1f) lc1 = p4; // H/2
  460. 0: r0 = [i0++] || r2 = [i1++];
  461. r1 = [i0++] || r3 = [i1++];
  462. r4 = bytepack(r0, r1);
  463. r5 = bytepack(r2, r3);
  464. lsetup (2f, 3f) lc0 = p5; // W/4
  465. 2: r0 = r0 >> 8(v) || [p0++] = r4; // yyyy-even
  466. r1 = r1 >> 8(v) || [p1++] = r5; // yyyy-odd
  467. r2 = r2 >> 8(v);
  468. r3 = r3 >> 8(v);
  469. r4 = byteop1p(r1:0, r3:2);
  470. r5 = byteop1p(r1:0, r3:2) (r);
  471. r6 = pack(r5.l, r4.l);
  472. r7 = pack(r5.h, r4.h) || r0 = [i0++] || r2 = [i1++];
  473. r6 = bytepack(r6, r7) || r1 = [i0++] || r3 = [i1++];
  474. r4 = bytepack(r0, r1) || w[i2++] = r6.l; // uu
  475. 3: r5 = bytepack(r2, r3) || w[i3++] = r6.h; // vv
  476. i0 += m0;
  477. i1 += m0;
  478. i2 += m1;
  479. i3 += m1;
  480. p0 = p0 + p2;
  481. 1: p1 = p1 + p2;
  482. (r7:4,p5:4) = [sp++];
  483. unlink;
  484. rts;
  485. DEFUN_END(yuyvtoyv12)