quickpreview.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /*
  2. * Fast but bad debayer method that scales and rotates by skipping source
  3. * pixels and doesn't interpolate any values at all
  4. */
  5. #include "quickpreview.h"
  6. #include <assert.h>
  7. #include <stdio.h>
  8. static inline uint32_t
  9. pack_rgb(uint8_t r, uint8_t g, uint8_t b)
  10. {
  11. return (r << 16) | (g << 8) | b;
  12. }
  13. static inline uint32_t
  14. convert_yuv_to_srgb(uint8_t y, uint8_t u, uint8_t v)
  15. {
  16. uint32_t r = 1.164f * y + 1.596f * (v - 128);
  17. uint32_t g = 1.164f * y - 0.813f * (v - 128) - 0.391f * (u - 128);
  18. uint32_t b = 1.164f * y + 2.018f * (u - 128);
  19. return pack_rgb(r, g, b);
  20. }
  21. static inline uint32_t
  22. apply_colormatrix(uint32_t color, const float *colormatrix)
  23. {
  24. if (!colormatrix) {
  25. return color;
  26. }
  27. uint32_t r = (color >> 16) * colormatrix[0] +
  28. ((color >> 8) & 0xFF) * colormatrix[1] +
  29. (color & 0xFF) * colormatrix[2];
  30. uint32_t g = (color >> 16) * colormatrix[3] +
  31. ((color >> 8) & 0xFF) * colormatrix[4] +
  32. (color & 0xFF) * colormatrix[5];
  33. uint32_t b = (color >> 16) * colormatrix[6] +
  34. ((color >> 8) & 0xFF) * colormatrix[7] +
  35. (color & 0xFF) * colormatrix[8];
  36. // Clip colors
  37. if (r > 0xFF)
  38. r = 0xFF;
  39. if (g > 0xFF)
  40. g = 0xFF;
  41. if (b > 0xFF)
  42. b = 0xFF;
  43. return pack_rgb(r, g, b);
  44. }
  45. static inline uint32_t
  46. coord_map(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int rotation,
  47. bool mirrored)
  48. {
  49. uint32_t x_r, y_r;
  50. if (rotation == 0) {
  51. x_r = x;
  52. y_r = y;
  53. } else if (rotation == 90) {
  54. x_r = y;
  55. y_r = height - x - 1;
  56. } else if (rotation == 270) {
  57. x_r = width - y - 1;
  58. y_r = x;
  59. } else {
  60. x_r = width - x - 1;
  61. y_r = height - y - 1;
  62. }
  63. if (mirrored) {
  64. x_r = width - x_r - 1;
  65. }
  66. uint32_t index = y_r * width + x_r;
  67. #ifdef DEBUG
  68. assert(index < width * height);
  69. #endif
  70. return index;
  71. }
  72. static void
  73. quick_preview_rggb8(uint32_t *dst, const uint32_t dst_width,
  74. const uint32_t dst_height, const uint8_t *src,
  75. const uint32_t src_width, const uint32_t src_height,
  76. const MPPixelFormat format, const uint32_t rotation,
  77. const bool mirrored, const float *colormatrix,
  78. const uint8_t blacklevel, const uint32_t skip)
  79. {
  80. uint32_t src_y = 0, dst_y = 0;
  81. while (src_y < src_height) {
  82. uint32_t src_x = 0, dst_x = 0;
  83. while (src_x < src_width) {
  84. uint32_t src_i = src_y * src_width + src_x;
  85. uint8_t b0 = src[src_i] - blacklevel;
  86. uint8_t b1 = src[src_i + 1] - blacklevel;
  87. uint8_t b2 = src[src_i + src_width + 1] - blacklevel;
  88. uint32_t color;
  89. switch (format) {
  90. case MP_PIXEL_FMT_BGGR8:
  91. color = pack_rgb(b2, b1, b0);
  92. break;
  93. case MP_PIXEL_FMT_GBRG8:
  94. color = pack_rgb(b2, b0, b1);
  95. break;
  96. case MP_PIXEL_FMT_GRBG8:
  97. color = pack_rgb(b1, b0, b2);
  98. break;
  99. case MP_PIXEL_FMT_RGGB8:
  100. color = pack_rgb(b0, b1, b2);
  101. break;
  102. default:
  103. assert(false);
  104. }
  105. color = apply_colormatrix(color, colormatrix);
  106. dst[coord_map(dst_x, dst_y, dst_width, dst_height, rotation,
  107. mirrored)] = color;
  108. src_x += 2 + 2 * skip;
  109. ++dst_x;
  110. }
  111. src_y += 2 + 2 * skip;
  112. ++dst_y;
  113. }
  114. }
  115. static void
  116. quick_preview_rggb10(uint32_t *dst, const uint32_t dst_width,
  117. const uint32_t dst_height, const uint8_t *src,
  118. const uint32_t src_width, const uint32_t src_height,
  119. const MPPixelFormat format, const uint32_t rotation,
  120. const bool mirrored, const float *colormatrix,
  121. const uint8_t blacklevel, const uint32_t skip)
  122. {
  123. assert(src_width % 2 == 0);
  124. uint32_t width_bytes = mp_pixel_format_width_to_bytes(format, src_width);
  125. uint32_t src_y = 0, dst_y = 0;
  126. while (src_y < src_height) {
  127. uint32_t src_x = 0, dst_x = 0;
  128. while (src_x < width_bytes) {
  129. uint32_t src_i = src_y * width_bytes + src_x;
  130. uint8_t b0 = src[src_i] - blacklevel;
  131. uint8_t b1 = src[src_i + 1] - blacklevel;
  132. uint8_t b2 = src[src_i + width_bytes + 1] - blacklevel;
  133. uint32_t color;
  134. switch (format) {
  135. case MP_PIXEL_FMT_BGGR10P:
  136. color = pack_rgb(b2, b1, b0);
  137. break;
  138. case MP_PIXEL_FMT_GBRG10P:
  139. color = pack_rgb(b2, b0, b1);
  140. break;
  141. case MP_PIXEL_FMT_GRBG10P:
  142. color = pack_rgb(b1, b0, b2);
  143. break;
  144. case MP_PIXEL_FMT_RGGB10P:
  145. color = pack_rgb(b0, b1, b2);
  146. break;
  147. default:
  148. assert(false);
  149. }
  150. color = apply_colormatrix(color, colormatrix);
  151. dst[coord_map(dst_x, dst_y, dst_width, dst_height, rotation,
  152. mirrored)] = color;
  153. uint32_t advance = 1 + skip;
  154. if (src_x % 5 == 0) {
  155. src_x += 2 * (advance % 2) + 5 * (advance / 2);
  156. } else {
  157. src_x += 3 * (advance % 2) + 5 * (advance / 2);
  158. }
  159. ++dst_x;
  160. }
  161. src_y += 2 + 2 * skip;
  162. ++dst_y;
  163. }
  164. }
  165. static void
  166. quick_preview_yuv(uint32_t *dst, const uint32_t dst_width, const uint32_t dst_height,
  167. const uint8_t *src, const uint32_t src_width,
  168. const uint32_t src_height, const MPPixelFormat format,
  169. const uint32_t rotation, const bool mirrored,
  170. const float *colormatrix, const uint32_t skip)
  171. {
  172. assert(src_width % 2 == 0);
  173. uint32_t width_bytes = src_width * 2;
  174. uint32_t unrot_dst_width = dst_width;
  175. if (rotation != 0 && rotation != 180) {
  176. unrot_dst_width = dst_height;
  177. }
  178. uint32_t src_y = 0, dst_y = 0;
  179. while (src_y < src_height) {
  180. uint32_t src_x = 0, dst_x = 0;
  181. while (src_x < width_bytes) {
  182. uint32_t src_i = src_y * width_bytes + src_x;
  183. uint8_t b0 = src[src_i];
  184. uint8_t b1 = src[src_i + 1];
  185. uint8_t b2 = src[src_i + 2];
  186. uint8_t b3 = src[src_i + 3];
  187. uint32_t color1, color2;
  188. switch (format) {
  189. case MP_PIXEL_FMT_UYVY:
  190. color1 = convert_yuv_to_srgb(b1, b0, b2);
  191. color2 = convert_yuv_to_srgb(b3, b0, b2);
  192. break;
  193. case MP_PIXEL_FMT_YUYV:
  194. color1 = convert_yuv_to_srgb(b0, b1, b3);
  195. color2 = convert_yuv_to_srgb(b2, b1, b3);
  196. break;
  197. default:
  198. assert(false);
  199. }
  200. color1 = apply_colormatrix(color1, colormatrix);
  201. color2 = apply_colormatrix(color2, colormatrix);
  202. uint32_t dst_i1 = coord_map(dst_x, dst_y, dst_width,
  203. dst_height, rotation, mirrored);
  204. dst[dst_i1] = color1;
  205. ++dst_x;
  206. // The last pixel needs to be skipped if we have an odd un-rotated width
  207. if (dst_x < unrot_dst_width) {
  208. uint32_t dst_i2 =
  209. coord_map(dst_x, dst_y, dst_width,
  210. dst_height, rotation, mirrored);
  211. dst[dst_i2] = color2;
  212. ++dst_x;
  213. }
  214. src_x += 4 + 4 * skip;
  215. }
  216. src_y += 1 + skip;
  217. ++dst_y;
  218. }
  219. }
  220. void
  221. quick_preview(uint32_t *dst, const uint32_t dst_width, const uint32_t dst_height,
  222. const uint8_t *src, const uint32_t src_width,
  223. const uint32_t src_height, const MPPixelFormat format,
  224. const uint32_t rotation, const bool mirrored, const float *colormatrix,
  225. const uint8_t blacklevel, const uint32_t skip)
  226. {
  227. switch (format) {
  228. case MP_PIXEL_FMT_BGGR8:
  229. case MP_PIXEL_FMT_GBRG8:
  230. case MP_PIXEL_FMT_GRBG8:
  231. case MP_PIXEL_FMT_RGGB8:
  232. quick_preview_rggb8(dst, dst_width, dst_height, src, src_width,
  233. src_height, format, rotation, mirrored,
  234. colormatrix, blacklevel, skip);
  235. break;
  236. case MP_PIXEL_FMT_BGGR10P:
  237. case MP_PIXEL_FMT_GBRG10P:
  238. case MP_PIXEL_FMT_GRBG10P:
  239. case MP_PIXEL_FMT_RGGB10P:
  240. quick_preview_rggb10(dst, dst_width, dst_height, src, src_width,
  241. src_height, format, rotation, mirrored,
  242. colormatrix, blacklevel, skip);
  243. break;
  244. case MP_PIXEL_FMT_UYVY:
  245. case MP_PIXEL_FMT_YUYV:
  246. quick_preview_yuv(dst, dst_width, dst_height, src, src_width,
  247. src_height, format, rotation, mirrored,
  248. colormatrix, skip);
  249. break;
  250. default:
  251. assert(false);
  252. }
  253. }
  254. static uint32_t
  255. div_ceil(uint32_t x, uint32_t y)
  256. {
  257. return x / y + !!(x % y);
  258. }
  259. void
  260. quick_preview_size(uint32_t *dst_width, uint32_t *dst_height, uint32_t *skip,
  261. const uint32_t preview_width, const uint32_t preview_height,
  262. const uint32_t src_width, const uint32_t src_height,
  263. const MPPixelFormat format, const int rotation)
  264. {
  265. uint32_t colors_x = mp_pixel_format_width_to_colors(format, src_width);
  266. uint32_t colors_y = mp_pixel_format_height_to_colors(format, src_height);
  267. if (rotation != 0 && rotation != 180) {
  268. uint32_t tmp = colors_x;
  269. colors_x = colors_y;
  270. colors_y = tmp;
  271. }
  272. uint32_t scale_x = colors_x / preview_width;
  273. uint32_t scale_y = colors_y / preview_height;
  274. if (scale_x > 0)
  275. --scale_x;
  276. if (scale_y > 0)
  277. --scale_y;
  278. *skip = scale_x > scale_y ? scale_x : scale_y;
  279. *dst_width = div_ceil(colors_x, (1 + *skip));
  280. if (*dst_width <= 0)
  281. *dst_width = 1;
  282. *dst_height = div_ceil(colors_y, (1 + *skip));
  283. if (*dst_height <= 0)
  284. *dst_height = 1;
  285. }