quickpreview.c 8.2 KB

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