quickpreview.c 9.5 KB

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