quickpreview.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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. /* Linear -> sRGB lookup table */
  9. static const int srgb[] = {
  10. 0, 12, 21, 28, 33, 38, 42, 46, 49, 52, 55, 58, 61, 63, 66, 68, 70,
  11. 73, 75, 77, 79, 81, 82, 84, 86, 88, 89, 91, 93, 94, 96, 97, 99, 100,
  12. 102, 103, 104, 106, 107, 109, 110, 111, 112, 114, 115, 116, 117, 118,
  13. 120, 121, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134,
  14. 135, 136, 137, 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147,
  15. 148, 149, 150, 151, 151, 152, 153, 154, 155, 156, 157, 157, 158, 159,
  16. 160, 161, 161, 162, 163, 164, 165, 165, 166, 167, 168, 168, 169, 170,
  17. 171, 171, 172, 173, 174, 174, 175, 176, 176, 177, 178, 179, 179, 180,
  18. 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189,
  19. 190, 191, 191, 192, 193, 193, 194, 194, 195, 196, 196, 197, 197, 198,
  20. 199, 199, 200, 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206,
  21. 207, 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214,
  22. 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222,
  23. 222, 223, 223, 224, 224, 225, 226, 226, 227, 227, 228, 228, 229, 229,
  24. 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236,
  25. 237, 237, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243,
  26. 243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249,
  27. 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255
  28. };
  29. static inline uint32_t pack_rgb(uint8_t r, uint8_t g, uint8_t b)
  30. {
  31. return (r << 16) | (g << 8) | b;
  32. }
  33. static inline uint32_t convert_yuv_to_srgb(uint8_t y, uint8_t u, uint8_t v)
  34. {
  35. uint32_t r = 1.164f * y + 1.596f * (v - 128);
  36. uint32_t g = 1.164f * y - 0.813f * (v - 128) - 0.391f * (u - 128);
  37. uint32_t b = 1.164f * y + 2.018f * (u - 128);
  38. return pack_rgb(r, g, b);
  39. }
  40. static inline uint32_t apply_colormatrix(uint32_t color, const float *colormatrix)
  41. {
  42. if (!colormatrix) {
  43. return color;
  44. }
  45. uint32_t r = (color >> 16) * colormatrix[0] + ((color >> 8) & 0xFF) * colormatrix[1] + (color & 0xFF) * colormatrix[2];
  46. uint32_t g = (color >> 16) * colormatrix[3] + ((color >> 8) & 0xFF) * colormatrix[4] + (color & 0xFF) * colormatrix[5];
  47. uint32_t b = (color >> 16) * colormatrix[6] + ((color >> 8) & 0xFF) * colormatrix[7] + (color & 0xFF) * colormatrix[8];
  48. return pack_rgb(r, g, b);
  49. }
  50. static inline uint32_t coord_map(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int rotation, bool mirrored)
  51. {
  52. uint32_t x_r, y_r;
  53. if (rotation == 0) {
  54. x_r = x;
  55. y_r = y;
  56. } else if (rotation == 90) {
  57. x_r = y;
  58. y_r = height - x - 1;
  59. } else if (rotation == 270) {
  60. x_r = width - y - 1;
  61. y_r = x;
  62. } else {
  63. x_r = width - x - 1;
  64. y_r = height - y - 1;
  65. }
  66. if (mirrored) {
  67. x_r = width - x_r - 1;
  68. }
  69. uint32_t index = y_r * width + x_r;
  70. #ifdef DEBUG
  71. assert(index < width * height);
  72. #endif
  73. return index;
  74. }
  75. static void quick_preview_rggb8(
  76. uint32_t *dst,
  77. const uint32_t dst_width,
  78. const uint32_t dst_height,
  79. const uint8_t *src,
  80. const uint32_t src_width,
  81. const uint32_t src_height,
  82. const MPPixelFormat format,
  83. const uint32_t rotation,
  84. const bool mirrored,
  85. const float *colormatrix,
  86. const uint8_t blacklevel,
  87. const uint32_t skip)
  88. {
  89. uint32_t src_y = 0, dst_y = 0;
  90. while (src_y < src_height) {
  91. uint32_t src_x = 0, dst_x = 0;
  92. while (src_x < src_width) {
  93. uint32_t src_i = src_y * src_width + src_x;
  94. uint8_t b0 = srgb[src[src_i] - blacklevel];
  95. uint8_t b1 = srgb[src[src_i + 1] - blacklevel];
  96. uint8_t b2 = srgb[src[src_i + src_width + 1] - blacklevel];
  97. uint32_t color;
  98. switch (format) {
  99. case MP_PIXEL_FMT_BGGR8:
  100. color = pack_rgb(b2, b1, b0);
  101. break;
  102. case MP_PIXEL_FMT_GBRG8:
  103. color = pack_rgb(b2, b0, b1);
  104. break;
  105. case MP_PIXEL_FMT_GRBG8:
  106. color = pack_rgb(b1, b0, b2);
  107. break;
  108. case MP_PIXEL_FMT_RGGB8:
  109. color = pack_rgb(b0, b1, b2);
  110. break;
  111. default:
  112. assert(false);
  113. }
  114. color = apply_colormatrix(color, colormatrix);
  115. // printf("?? %d:%d\n", dst_x, dst_y);
  116. dst[coord_map(dst_x, dst_y, dst_width, dst_height, rotation, mirrored)] = color;
  117. src_x += 2 + 2 * skip;
  118. ++dst_x;
  119. }
  120. src_y += 2 + 2 * skip;
  121. ++dst_y;
  122. }
  123. }
  124. static void quick_preview_rggb10(
  125. uint32_t *dst,
  126. const uint32_t dst_width,
  127. const uint32_t dst_height,
  128. const uint8_t *src,
  129. const uint32_t src_width,
  130. const uint32_t src_height,
  131. const MPPixelFormat format,
  132. const uint32_t rotation,
  133. const bool mirrored,
  134. const float *colormatrix,
  135. const uint8_t blacklevel,
  136. const uint32_t skip)
  137. {
  138. assert(src_width % 2 == 0);
  139. uint32_t width_bytes = mp_pixel_format_width_to_bytes(format, src_width);
  140. uint32_t src_y = 0, dst_y = 0;
  141. while (src_y < src_height) {
  142. uint32_t src_x = 0, dst_x = 0;
  143. while (src_x < width_bytes) {
  144. uint32_t src_i = src_y * width_bytes + src_x;
  145. uint8_t b0 = srgb[src[src_i] - blacklevel];
  146. uint8_t b1 = srgb[src[src_i + 1] - blacklevel];
  147. uint8_t b2 = srgb[src[src_i + width_bytes + 1] - blacklevel];
  148. uint32_t color;
  149. switch (format) {
  150. case MP_PIXEL_FMT_BGGR10P:
  151. color = pack_rgb(b2, b1, b0);
  152. break;
  153. case MP_PIXEL_FMT_GBRG10P:
  154. color = pack_rgb(b2, b0, b1);
  155. break;
  156. case MP_PIXEL_FMT_GRBG10P:
  157. color = pack_rgb(b1, b0, b2);
  158. break;
  159. case MP_PIXEL_FMT_RGGB10P:
  160. color = pack_rgb(b0, b1, b2);
  161. break;
  162. default:
  163. assert(false);
  164. }
  165. color = apply_colormatrix(color, colormatrix);
  166. dst[coord_map(dst_x, dst_y, dst_width, dst_height, rotation, mirrored)] = color;
  167. uint32_t advance = 1 + skip;
  168. if (src_x % 5 == 0) {
  169. src_x += 2 * (advance % 2) + 5 * (advance / 2);
  170. } else {
  171. src_x += 3 * (advance % 2) + 5 * (advance / 2);
  172. }
  173. ++dst_x;
  174. }
  175. src_y += 2 + 2 * skip;
  176. ++dst_y;
  177. }
  178. }
  179. static void quick_preview_yuv(
  180. uint32_t *dst,
  181. const uint32_t dst_width,
  182. const uint32_t dst_height,
  183. const uint8_t *src,
  184. const uint32_t src_width,
  185. const uint32_t src_height,
  186. const MPPixelFormat format,
  187. const uint32_t rotation,
  188. const bool mirrored,
  189. const float *colormatrix,
  190. const uint32_t skip)
  191. {
  192. assert(src_width % 2 == 0);
  193. uint32_t width_bytes = src_width * 2;
  194. uint32_t src_y = 0, dst_y = 0;
  195. while (src_y < src_height) {
  196. uint32_t src_x = 0, dst_x = 0;
  197. while (src_x < width_bytes) {
  198. uint32_t src_i = src_y * width_bytes + src_x;
  199. uint8_t b0 = src[src_i];
  200. uint8_t b1 = src[src_i + 1];
  201. uint8_t b2 = src[src_i + 2];
  202. uint8_t b3 = src[src_i + 3];
  203. uint32_t color1, color2;
  204. switch (format) {
  205. case MP_PIXEL_FMT_UYVY:
  206. color1 = convert_yuv_to_srgb(b1, b0, b2);
  207. color2 = convert_yuv_to_srgb(b3, b0, b2);
  208. break;
  209. case MP_PIXEL_FMT_YUYV:
  210. color1 = convert_yuv_to_srgb(b0, b1, b3);
  211. color2 = convert_yuv_to_srgb(b2, b1, b3);
  212. break;
  213. default:
  214. assert(false);
  215. }
  216. color1 = apply_colormatrix(color1, colormatrix);
  217. color2 = apply_colormatrix(color2, colormatrix);
  218. uint32_t dst_i1 = coord_map(dst_x, dst_y, dst_width, dst_height, rotation, mirrored);
  219. dst[dst_i1] = color1;
  220. ++dst_x;
  221. uint32_t dst_i2 = coord_map(dst_x, dst_y, dst_width, dst_height, rotation, mirrored);
  222. dst[dst_i2] = color2;
  223. ++dst_x;
  224. src_x += 4 + 4 * skip;
  225. }
  226. src_y += 1 + skip;
  227. ++dst_y;
  228. }
  229. }
  230. void quick_preview(
  231. uint32_t *dst,
  232. const uint32_t dst_width,
  233. const uint32_t dst_height,
  234. const uint8_t *src,
  235. const uint32_t src_width,
  236. const uint32_t src_height,
  237. const MPPixelFormat format,
  238. const uint32_t rotation,
  239. const bool mirrored,
  240. const float *colormatrix,
  241. const uint8_t blacklevel,
  242. const uint32_t skip)
  243. {
  244. switch (format) {
  245. case MP_PIXEL_FMT_BGGR8:
  246. case MP_PIXEL_FMT_GBRG8:
  247. case MP_PIXEL_FMT_GRBG8:
  248. case MP_PIXEL_FMT_RGGB8:
  249. quick_preview_rggb8(
  250. dst,
  251. dst_width,
  252. dst_height,
  253. src,
  254. src_width,
  255. src_height,
  256. format,
  257. rotation,
  258. mirrored,
  259. colormatrix,
  260. blacklevel,
  261. skip);
  262. break;
  263. case MP_PIXEL_FMT_BGGR10P:
  264. case MP_PIXEL_FMT_GBRG10P:
  265. case MP_PIXEL_FMT_GRBG10P:
  266. case MP_PIXEL_FMT_RGGB10P:
  267. quick_preview_rggb10(
  268. dst,
  269. dst_width,
  270. dst_height,
  271. src,
  272. src_width,
  273. src_height,
  274. format,
  275. rotation,
  276. mirrored,
  277. colormatrix,
  278. blacklevel,
  279. skip);
  280. break;
  281. case MP_PIXEL_FMT_UYVY:
  282. case MP_PIXEL_FMT_YUYV:
  283. quick_preview_yuv(
  284. dst,
  285. dst_width,
  286. dst_height,
  287. src,
  288. src_width,
  289. src_height,
  290. format,
  291. rotation,
  292. mirrored,
  293. colormatrix,
  294. skip);
  295. break;
  296. default:
  297. assert(false);
  298. }
  299. }
  300. static uint32_t div_ceil(uint32_t x, uint32_t y)
  301. {
  302. return x/y + !!(x % y);
  303. }
  304. void quick_preview_size(
  305. uint32_t *dst_width,
  306. uint32_t *dst_height,
  307. uint32_t *skip,
  308. const uint32_t preview_width,
  309. const uint32_t preview_height,
  310. const uint32_t src_width,
  311. const uint32_t src_height,
  312. const MPPixelFormat format,
  313. const int rotation)
  314. {
  315. uint32_t colors_x = mp_pixel_format_width_to_colors(format, src_width);
  316. uint32_t colors_y = mp_pixel_format_height_to_colors(format, src_height);
  317. if (rotation != 0 && rotation != 180) {
  318. uint32_t tmp = colors_x;
  319. colors_x = colors_y;
  320. colors_y = tmp;
  321. }
  322. uint32_t scale_x = colors_x / preview_width;
  323. uint32_t scale_y = colors_y / preview_height;
  324. if (scale_x > 0)
  325. --scale_x;
  326. if (scale_y > 0)
  327. --scale_y;
  328. *skip = scale_x > scale_y ? scale_x : scale_y;
  329. *dst_width = div_ceil(colors_x, (1 + *skip));
  330. if (*dst_width <= 0)
  331. *dst_width = 1;
  332. *dst_height = div_ceil(colors_y, (1 + *skip));
  333. if (*dst_height <= 0)
  334. *dst_height = 1;
  335. }