/Avc/yuv420rgb888c.cpp

http://github.com/mbebenita/Broadway · C++ · 194 lines · 111 code · 9 blank · 74 comment · 15 complexity · 286c551db5d5abf5a4e155e44325560b MD5 · raw file

  1. /* YUV-> RGB conversion code.
  2. *
  3. * Copyright (C) 2011 Robin Watts (robin@wss.co.uk) for Pinknoise
  4. * Productions Ltd.
  5. *
  6. * Licensed under the BSD license. See 'COPYING' for details of
  7. * (non-)warranty.
  8. *
  9. *
  10. * The algorithm used here is based heavily on one created by Sophie Wilson
  11. * of Acorn/e-14/Broadcomm. Many thanks.
  12. *
  13. * Additional tweaks (in the fast fixup code) are from Paul Gardiner.
  14. *
  15. * The old implementation of YUV -> RGB did:
  16. *
  17. * R = CLAMP((Y-16)*1.164 + 1.596*V)
  18. * G = CLAMP((Y-16)*1.164 - 0.391*U - 0.813*V)
  19. * B = CLAMP((Y-16)*1.164 + 2.018*U )
  20. *
  21. * We're going to bend that here as follows:
  22. *
  23. * R = CLAMP(y + 1.596*V)
  24. * G = CLAMP(y - 0.383*U - 0.813*V)
  25. * B = CLAMP(y + 1.976*U )
  26. *
  27. * where y = 0 for Y <= 16,
  28. * y = ( Y-16)*1.164, for 16 < Y <= 239,
  29. * y = (239-16)*1.164, for 239 < Y
  30. *
  31. * i.e. We clamp Y to the 16 to 239 range (which it is supposed to be in
  32. * anyway). We then pick the B_U factor so that B never exceeds 511. We then
  33. * shrink the G_U factor in line with that to avoid a colour shift as much as
  34. * possible.
  35. *
  36. * We're going to use tables to do it faster, but rather than doing it using
  37. * 5 tables as as the above suggests, we're going to do it using just 3.
  38. *
  39. * We do this by working in parallel within a 32 bit word, and using one
  40. * table each for Y U and V.
  41. *
  42. * Source Y values are 0 to 255, so 0.. 260 after scaling
  43. * Source U values are -128 to 127, so -49.. 49(G), -253..251(B) after
  44. * Source V values are -128 to 127, so -204..203(R), -104..103(G) after
  45. *
  46. * So total summed values:
  47. * -223 <= R <= 481, -173 <= G <= 431, -253 <= B < 511
  48. *
  49. * We need to pack R G and B into a 32 bit word, and because of Bs range we
  50. * need 2 bits above the valid range of B to detect overflow, and another one
  51. * to detect the sense of the overflow. We therefore adopt the following
  52. * representation:
  53. *
  54. * osGGGGGgggggosBBBBBbbbosRRRRRrrr
  55. *
  56. * Each such word breaks down into 3 ranges.
  57. *
  58. * osGGGGGggggg osBBBBBbbb osRRRRRrrr
  59. *
  60. * Thus we have 8 bits for each B and R table entry, and 10 bits for G (good
  61. * as G is the most noticable one). The s bit for each represents the sign,
  62. * and o represents the overflow.
  63. *
  64. * For R and B we pack the table by taking the 11 bit representation of their
  65. * values, and toggling bit 10 in the U and V tables.
  66. *
  67. * For the green case we calculate 4*G (thus effectively using 10 bits for the
  68. * valid range) truncate to 12 bits. We toggle bit 11 in the Y table.
  69. */
  70. #include "yuv2rgb.h"
  71. enum
  72. {
  73. FLAGS = 0x40080100
  74. };
  75. #define READUV(U,V) (tables[256 + (U)] + tables[512 + (V)])
  76. #define READY(Y) tables[Y]
  77. #define FIXUP(Y) \
  78. do { \
  79. int tmp = (Y) & FLAGS; \
  80. if (tmp != 0) \
  81. { \
  82. tmp -= tmp>>8; \
  83. (Y) |= tmp; \
  84. tmp = FLAGS & ~(Y>>1); \
  85. (Y) += tmp>>8; \
  86. } \
  87. } while (0 == 1)
  88. #define STORE(Y,DSTPTR) \
  89. do { \
  90. uint32_t Y2 = (Y); \
  91. uint8_t *DSTPTR2 = (DSTPTR); \
  92. (DSTPTR2)[0] = (Y2); \
  93. (DSTPTR2)[1] = (Y2)>>22; \
  94. (DSTPTR2)[2] = (Y2)>>11; \
  95. } while (0 == 1)
  96. void yuv420_2_rgb888(uint8_t *dst_ptr,
  97. const uint8_t *y_ptr,
  98. const uint8_t *u_ptr,
  99. const uint8_t *v_ptr,
  100. int32_t width,
  101. int32_t height,
  102. int32_t y_span,
  103. int32_t uv_span,
  104. int32_t dst_span,
  105. const uint32_t *tables,
  106. int32_t dither)
  107. {
  108. height -= 1;
  109. while (height > 0)
  110. {
  111. height -= width<<16;
  112. height += 1<<16;
  113. while (height < 0)
  114. {
  115. /* Do 2 column pairs */
  116. uint32_t uv, y0, y1;
  117. uv = READUV(*u_ptr++,*v_ptr++);
  118. y1 = uv + READY(y_ptr[y_span]);
  119. y0 = uv + READY(*y_ptr++);
  120. FIXUP(y1);
  121. FIXUP(y0);
  122. STORE(y1, &dst_ptr[dst_span]);
  123. STORE(y0, dst_ptr);
  124. dst_ptr += 3;
  125. y1 = uv + READY(y_ptr[y_span]);
  126. y0 = uv + READY(*y_ptr++);
  127. FIXUP(y1);
  128. FIXUP(y0);
  129. STORE(y1, &dst_ptr[dst_span]);
  130. STORE(y0, dst_ptr);
  131. dst_ptr += 3;
  132. height += (2<<16);
  133. }
  134. if ((height>>16) == 0)
  135. {
  136. /* Trailing column pair */
  137. uint32_t uv, y0, y1;
  138. uv = READUV(*u_ptr,*v_ptr);
  139. y1 = uv + READY(y_ptr[y_span]);
  140. y0 = uv + READY(*y_ptr++);
  141. FIXUP(y1);
  142. FIXUP(y0);
  143. STORE(y0, &dst_ptr[dst_span]);
  144. STORE(y1, dst_ptr);
  145. dst_ptr += 3;
  146. }
  147. dst_ptr += dst_span*2-width*3;
  148. y_ptr += y_span*2-width;
  149. u_ptr += uv_span-(width>>1);
  150. v_ptr += uv_span-(width>>1);
  151. height = (height<<16)>>16;
  152. height -= 2;
  153. }
  154. if (height == 0)
  155. {
  156. /* Trail row */
  157. height -= width<<16;
  158. height += 1<<16;
  159. while (height < 0)
  160. {
  161. /* Do a row pair */
  162. uint32_t uv, y0, y1;
  163. uv = READUV(*u_ptr++,*v_ptr++);
  164. y1 = uv + READY(*y_ptr++);
  165. y0 = uv + READY(*y_ptr++);
  166. FIXUP(y1);
  167. FIXUP(y0);
  168. STORE(y1, dst_ptr);
  169. dst_ptr += 3;
  170. STORE(y0, dst_ptr);
  171. dst_ptr += 3;
  172. height += (2<<16);
  173. }
  174. if ((height>>16) == 0)
  175. {
  176. /* Trailing pix */
  177. uint32_t uv, y0;
  178. uv = READUV(*u_ptr++,*v_ptr++);
  179. y0 = uv + READY(*y_ptr++);
  180. FIXUP(y0);
  181. STORE(y0, dst_ptr);
  182. dst_ptr += 3;
  183. }
  184. }
  185. }