convert.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2021 StarFive Technology Co., Ltd.
  4. */
  5. #include "common.h"
  6. static int g_screen_width = 0;
  7. static int g_screen_height = 0;
  8. static int g_screen_bpp = 0;
  9. static int g_screen_size = 0;
  10. static int g_screen_distype = 0; // STF_DISP_FB or STF_DISP_DRM
  11. void update_videocvt_param(int distype, int scr_width, int scr_height,
  12. int scr_bpp, int scr_size)
  13. {
  14. g_screen_distype = distype;
  15. g_screen_width = scr_width;
  16. g_screen_height = scr_height;
  17. g_screen_bpp = scr_bpp;
  18. g_screen_size = scr_size;
  19. }
  20. int yuyv_resize(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight)
  21. {
  22. int rows;
  23. const uint8_t *YUVindata;
  24. uint8_t *YUVoutdata; /* YUV and RGB pointer */
  25. int YUVinpos; /* Y U V offset */
  26. int width, height;
  27. int x_offset, y_offset;
  28. uint32_t start_timems;
  29. uint32_t end_timems;
  30. struct timeval ts_start, ts_end;
  31. static uint8_t *tmp = NULL;
  32. if (!tmp)
  33. {
  34. tmp = malloc(g_screen_size);
  35. if (tmp)
  36. {
  37. // for YUYV buffer, set it to black
  38. for ( rows = 0; rows < g_screen_size; rows++)
  39. {
  40. if (rows == 0 || rows % 2 == 0)
  41. {
  42. //even is Y
  43. tmp[rows] = 0;
  44. }
  45. else
  46. {
  47. //odd is U or V
  48. tmp[rows] = 128;
  49. }
  50. }
  51. }
  52. }
  53. assert(tmp);
  54. gettimeofday(&ts_start, NULL);
  55. width = imgWidth > g_screen_width ? g_screen_width : imgWidth;
  56. height = imgHeight > g_screen_height ? g_screen_height : imgHeight;
  57. x_offset = (g_screen_width - width) / 2;
  58. y_offset = (g_screen_height - height) / 2;
  59. YUVindata = inBuf;
  60. YUVoutdata = tmp;
  61. if (imgWidth == g_screen_width) {
  62. YUVinpos = (y_offset * g_screen_width + x_offset) * 2;
  63. memcpy(&tmp[YUVinpos], inBuf, imgWidth * height * 2);
  64. memcpy(&outBuf[YUVinpos], &tmp[YUVinpos], imgWidth * height * 2);
  65. // memcpy(&outBuf[YUVinpos], inBuf, imgWidth * height * 2);
  66. gettimeofday(&ts_end, NULL);
  67. start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000;
  68. end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000;
  69. // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int));
  70. //free(tmp);
  71. return 0;
  72. }
  73. /* two bytes for one pixels */
  74. for(rows = 0; rows < height; rows++)
  75. {
  76. // g_screen_width, g_screen_height g_screen_bpp
  77. YUVoutdata = tmp + ((rows + y_offset) * g_screen_width + x_offset) * 2;
  78. YUVinpos = rows * imgWidth * 2;
  79. memcpy(YUVoutdata, &YUVindata[YUVinpos], imgWidth * 2);
  80. }
  81. gettimeofday(&ts_end, NULL);
  82. start_timems = ts_start.tv_sec * 1000000 + ts_start.tv_usec;
  83. end_timems = ts_end.tv_sec * 1000000 + ts_end.tv_usec;
  84. // printf("%s: convert use %dus\n", __func__, end_timems - start_timems);
  85. gettimeofday(&ts_start, NULL);
  86. memcpy(outBuf, tmp, g_screen_size);
  87. gettimeofday(&ts_end, NULL);
  88. start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000;
  89. end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000;
  90. // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int));
  91. //free(tmp);
  92. return 0;
  93. }
  94. int convert_yuyv_to_nv12(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int is_yuyv)
  95. {
  96. int rows, cols;
  97. const uint8_t *YUVdata;
  98. uint8_t *nv12data;
  99. int Ypos;
  100. int fb_Ypos, fb_Upos, fb_Vpos;
  101. int width, height;
  102. int x_offset, y_offset;
  103. uint32_t start_timems;
  104. uint32_t end_timems;
  105. struct timeval ts_start, ts_end;
  106. static uint8_t *tmp = NULL;
  107. if (!tmp)
  108. {
  109. tmp = malloc(g_screen_size);
  110. if (tmp)
  111. {
  112. // for NV12 buffer, set it to black
  113. memset(tmp, 0, g_screen_size / 3 * 2);
  114. memset(tmp + g_screen_size / 3 * 2, 128, g_screen_size / 3);
  115. }
  116. }
  117. assert(tmp);
  118. gettimeofday(&ts_start, NULL);
  119. width = imgWidth > g_screen_width ? g_screen_width : imgWidth;
  120. height = imgHeight > g_screen_height ? g_screen_height : imgHeight;
  121. x_offset = (g_screen_width - width) / 2;
  122. y_offset = (g_screen_height - height) / 2;
  123. YUVdata = inBuf;
  124. nv12data = tmp;
  125. /* two bytes for every pixels */
  126. for(rows = 0; rows < height; rows++)
  127. {
  128. // g_screen_width, g_screen_height g_screen_bpp
  129. fb_Ypos = ((rows + y_offset) * g_screen_width + x_offset);
  130. fb_Upos = ((rows + y_offset) / 2 * g_screen_width / 2 + x_offset / 2) * 2;
  131. fb_Upos = g_screen_width * g_screen_height + fb_Upos;
  132. fb_Vpos = fb_Upos + 1;
  133. Ypos = rows * imgWidth * 2;
  134. for (cols = 0; cols < width; cols += 2) {
  135. nv12data[fb_Ypos+cols] = YUVdata[Ypos+cols*2];
  136. nv12data[fb_Ypos+cols+1] = YUVdata[Ypos+cols*2+2];
  137. nv12data[fb_Upos+cols] = YUVdata[Ypos+cols*2+1];
  138. nv12data[fb_Vpos+cols] = YUVdata[Ypos+cols*2+3];
  139. }
  140. }
  141. gettimeofday(&ts_end, NULL);
  142. start_timems = ts_start.tv_sec * 1000000 + ts_start.tv_usec;
  143. end_timems = ts_end.tv_sec * 1000000 + ts_end.tv_usec;
  144. // printf("%s: convert use %dus\n", __func__, end_timems - start_timems);
  145. gettimeofday(&ts_start, NULL);
  146. memcpy(outBuf, tmp, g_screen_size);
  147. gettimeofday(&ts_end, NULL);
  148. start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000;
  149. end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000;
  150. // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int));
  151. //free(tmp);
  152. return 0;
  153. }
  154. int convert_nv21_to_nv12(const uint8_t *inBuf, uint8_t *outBuf,
  155. int imgWidth, int imgHeight, int uv_changed)
  156. {
  157. int rows, cols;
  158. const uint8_t *nv21data;
  159. uint8_t *nv12data;
  160. int Ypos, Upos, Vpos;
  161. int fb_Ypos, fb_Upos, fb_Vpos;
  162. int width, height;
  163. int x_offset, y_offset;
  164. static uint8_t *tmp = NULL;
  165. uint32_t start_timems;
  166. uint32_t end_timems;
  167. struct timeval ts_start, ts_end;
  168. if (!tmp)
  169. {
  170. tmp = malloc(g_screen_size);
  171. if (tmp)
  172. {
  173. // for NV12 buffer, set it to black
  174. memset(tmp, 0, g_screen_size / 3 * 2);
  175. memset(tmp + g_screen_size / 3 * 2, 128, g_screen_size / 3);
  176. }
  177. }
  178. assert(tmp);
  179. gettimeofday(&ts_start, NULL);
  180. width = imgWidth > g_screen_width ? g_screen_width : imgWidth;
  181. height = imgHeight > g_screen_height ? g_screen_height : imgHeight;
  182. x_offset = (g_screen_width - width) / 2;
  183. y_offset = (g_screen_height - height) / 2;
  184. nv21data = inBuf;
  185. nv12data = tmp;
  186. // printf("[%s,%d]:imgWidth=%d, imgHeight=%d, g_screen_width=%d g_screen_height=%d g_screen_bpp=%d\n",__FUNCTION__,__LINE__,
  187. // imgWidth, imgHeight, g_screen_width, g_screen_height, g_screen_bpp);
  188. // below for same image size and not uv changed
  189. if (imgWidth == g_screen_width && !uv_changed) {
  190. fb_Ypos = y_offset * g_screen_width + x_offset;
  191. fb_Upos = (y_offset / 2 * g_screen_width / 2 + x_offset / 2) * 2;
  192. fb_Upos = g_screen_width * g_screen_height + fb_Upos;
  193. Upos = imgWidth * imgHeight;
  194. if (STF_DISP_FB == g_screen_distype) {
  195. // TODO: it is strange that with tmp buffer will more faster for framebuf
  196. memcpy(&tmp[fb_Ypos], inBuf, imgWidth * height);
  197. memcpy(&tmp[fb_Upos], &inBuf[Upos], imgWidth * height / 2);
  198. memcpy(&outBuf[fb_Ypos], &tmp[fb_Ypos], imgWidth * height);
  199. memcpy(&outBuf[fb_Upos], &tmp[fb_Upos], imgWidth * height / 2);
  200. } else {
  201. memcpy(&outBuf[fb_Ypos], inBuf, imgWidth * height);
  202. memcpy(&outBuf[fb_Upos], &inBuf[Upos], imgWidth * height / 2);
  203. }
  204. //free(tmp);
  205. return 0;
  206. }
  207. /* two bytes for every pixels */
  208. for(rows = 0; rows < height; rows+=2)
  209. {
  210. // g_screen_width, g_screen_height g_screen_bpp
  211. fb_Ypos = ((rows + y_offset) * g_screen_width + x_offset);
  212. fb_Upos = ((rows + y_offset) / 2 * g_screen_width / 2 + x_offset / 2) * 2;
  213. fb_Upos = g_screen_width * g_screen_height + fb_Upos;
  214. fb_Vpos = fb_Upos + 1;
  215. Ypos = rows * imgWidth;
  216. Upos = imgWidth * imgHeight + Ypos / 2;
  217. Vpos = Upos + 1;
  218. memcpy(&nv12data[fb_Ypos], &nv21data[Ypos], width);
  219. memcpy(&nv12data[fb_Ypos+g_screen_width], &nv21data[Ypos+imgWidth], width);
  220. if (uv_changed) {
  221. for (cols = 0; cols < width; cols += 2) {
  222. nv12data[fb_Upos+cols] = nv21data[Vpos+cols];
  223. nv12data[fb_Vpos+cols] = nv21data[Upos+cols];
  224. }
  225. } else {
  226. memcpy(&nv12data[fb_Upos], &nv21data[Upos], width);
  227. }
  228. }
  229. gettimeofday(&ts_end, NULL);
  230. start_timems = ts_start.tv_sec * 1000000 + ts_start.tv_usec;
  231. end_timems = ts_end.tv_sec * 1000000 + ts_end.tv_usec;
  232. // printf("%s: convert use %dus\n", __func__, end_timems - start_timems);
  233. gettimeofday(&ts_start, NULL);
  234. memcpy(outBuf, tmp, g_screen_size);
  235. gettimeofday(&ts_end, NULL);
  236. start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000;
  237. end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000;
  238. // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int));
  239. //free(tmp);
  240. return 0;
  241. }
  242. int convert_nv21_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int is_nv21)
  243. {
  244. int rows ,cols;
  245. int y, u, v, r, g, b;
  246. const uint8_t *YUVdata;
  247. uint8_t *RGBdata;
  248. int Ypos, Upos, Vpos;
  249. uint32_t i = 0;
  250. int width, height;
  251. int x_offset, y_offset;
  252. uint8_t *tmp = malloc(g_screen_size);
  253. uint32_t start_timems;
  254. uint32_t end_timems;
  255. struct timeval ts_start, ts_end;
  256. if (!tmp)
  257. return -1;
  258. gettimeofday(&ts_start, NULL);
  259. width = imgWidth > g_screen_width ? g_screen_width : imgWidth;
  260. height = imgHeight > g_screen_height ? g_screen_height : imgHeight;
  261. x_offset = (g_screen_width - width) / 2;
  262. y_offset = (g_screen_height - height) / 2;
  263. YUVdata = inBuf;
  264. RGBdata = tmp;
  265. /* two bytes for every pixels */
  266. for(rows = 0; rows < height; rows++)
  267. {
  268. // g_screen_width, g_screen_height g_screen_bpp
  269. RGBdata = tmp + ((rows + y_offset) * g_screen_width + x_offset) * g_screen_bpp / 8;
  270. Ypos = rows * imgWidth;
  271. Vpos = Upos = imgWidth * imgHeight + Ypos / 2;
  272. if (is_nv21)
  273. Vpos = Upos + 1;
  274. else
  275. Upos = Vpos + 1;
  276. i = 0;
  277. for (cols = 0; cols < width; cols++)
  278. {
  279. y = YUVdata[Ypos];
  280. u = YUVdata[Upos] - 128;
  281. v = YUVdata[Vpos] - 128;
  282. r = y + v + ((v * 103) >> 8);
  283. g = y - ((u * 88) >> 8) - ((v * 183) >> 8);
  284. b = y + u + ((u * 198) >> 8);
  285. r = r > 255 ? 255 : (r < 0 ? 0 : r);
  286. g = g > 255 ? 255 : (g < 0 ? 0 : g);
  287. b = b > 255 ? 255 : (b < 0 ? 0 : b);
  288. /* low -> high r g b */
  289. if (g_screen_bpp == 16) { // RGB565
  290. *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g low 5bit,b high 5bit */
  291. *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r high 5bit,g high 3bit */
  292. } else if (g_screen_bpp == 24) { // RGB888
  293. *(RGBdata ++) = b;
  294. *(RGBdata ++) = g;
  295. *(RGBdata ++) = r;
  296. } else { // RGB8888
  297. *(RGBdata ++) = b;
  298. *(RGBdata ++) = g;
  299. *(RGBdata ++) = r;
  300. *(RGBdata ++) = 0xFF;
  301. }
  302. Ypos++;
  303. i++;
  304. /* every 4 time y to update 1 time uv */
  305. if(!(i & 0x03))
  306. {
  307. Vpos = Upos = imgWidth * imgHeight + Ypos/2;
  308. if (is_nv21)
  309. Vpos = Upos + 1;
  310. else
  311. Upos = Vpos + 1;
  312. }
  313. }
  314. }
  315. gettimeofday(&ts_end, NULL);
  316. start_timems = ts_start.tv_sec * 1000000 + ts_start.tv_usec;
  317. end_timems = ts_end.tv_sec * 1000000 + ts_end.tv_usec;
  318. // printf("%s: convert use %dus\n", __func__, end_timems - start_timems);
  319. gettimeofday(&ts_start, NULL);
  320. #if 1
  321. memcpy(outBuf, tmp, g_screen_size);
  322. #else
  323. int *p_outBuf, *p_tmp;
  324. int size = g_screen_size/4;
  325. p_outBuf = outBuf;
  326. p_tmp = tmp;
  327. for (i = 0; i < size; i++)
  328. p_outBuf[i] = p_tmp[i];
  329. #endif
  330. gettimeofday(&ts_end, NULL);
  331. start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000;
  332. end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000;
  333. // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int));
  334. free(tmp);
  335. return 0;
  336. }
  337. //Y' = 0.257*R' + 0.504*G' + 0.098*B' + 16
  338. static int Rgb2Y(int r0, int g0, int b0)
  339. {
  340. // float y0 = 0.257f*r0 + 0.504f*g0 + 0.098f*b0 + 16.0f;
  341. // int y0 = (257*r0 + 504*g0 + 98*b0)/1000 + 16;
  342. // Y = (77*R + 150*G + 29*B)>>8;
  343. int y0 = (77*r0+150*g0+29*b0) >> 8;
  344. return y0;
  345. }
  346. //U equals Cb'
  347. //Cb' = -0.148*R' - 0.291*G' + 0.439*B' + 128
  348. static int Rgb2U(int r0, int g0, int b0)
  349. {
  350. // float u0 = -0.148f*r0 - 0.291f*g0 + 0.439f*b0 + 128.0f;
  351. // int u0 = (-148*r0 - 291*g0 + 439*b0)/1000 + 128;
  352. // U = ((-44*R - 87*G + 131*B)>>8) + 128;
  353. int u0 = ((-44*r0 - 87*g0 + 131*b0)>>8) + 128;
  354. return u0;
  355. }
  356. //V equals Cr'
  357. //Cr' = 0.439*R' - 0.368*G' - 0.071*B' + 128
  358. static int Rgb2V(int r0, int g0, int b0)
  359. {
  360. // float v0 = 0.439f*r0 - 0.368f*g0 - 0.071f*b0 + 128.0f;
  361. // int v0 = (439*r0 - 368*g0 - 71*b0)/1000 + 128;
  362. // V = ((131*R - 110*G - 21*B)>>8) + 128 ;
  363. int v0 = ((131*r0 - 110*g0 - 21*b0)>>8) + 128;
  364. return v0;
  365. }
  366. //Convert two rows from RGB to two Y rows, and one row of interleaved U,V.
  367. //I0 and I1 points two sequential source rows.
  368. //I0 -> rgbrgbrgbrgbrgbrgb...
  369. //I1 -> rgbrgbrgbrgbrgbrgb...
  370. //Y0 and Y1 points two sequential destination rows of Y plane.
  371. //Y0 -> yyyyyy
  372. //Y1 -> yyyyyy
  373. //UV0 points destination rows of interleaved UV plane.
  374. //UV0 -> uvuvuv
  375. static void Rgb2NV12TwoRows(const uint8_t I0[],
  376. const uint8_t I1[],
  377. int step,
  378. const int image_width,
  379. uint8_t Y0[],
  380. uint8_t Y1[],
  381. uint8_t UV0[])
  382. {
  383. int x; //Column index
  384. //Process 4 source pixels per iteration (2 pixels of row I0 and 2 pixels of row I1).
  385. for (x = 0; x < image_width; x += 2)
  386. {
  387. //Load R,G,B elements from first row (and convert to int).
  388. uint8_t b00 = (I0[x*step + 0] & 0x1F) << 3;
  389. uint8_t g00 = ((I0[x*step + 1] & 0x7) << 3 | I0[x*step + 0] >> 5) << 2;
  390. uint8_t r00 = I0[x*step + 1] & (~0x7);
  391. //Load next R,G,B elements from first row (and convert to int).
  392. uint8_t b01 = (I0[x*step + step+0] & 0x1F) << 3;
  393. uint8_t g01 = ((I0[x*step + step+1] & 0x7) << 3 | I0[x*step + step+0] >> 5) << 2;
  394. uint8_t r01 = I0[x*step + step+1] & (~0x7);
  395. //Load R,G,B elements from second row (and convert to int).
  396. uint8_t b10 = (I1[x*step + 0] & 0x1F) << 3;
  397. uint8_t g10 = ((I1[x*step + 1] & 0x7) << 3 | I1[x*step + 0] >> 5) << 2;
  398. uint8_t r10 = I1[x*step + 1] & (~0x7);
  399. //Load next R,G,B elements from second row (and convert to int).
  400. uint8_t b11 = (I1[x*step + step+0] & 0x1F) << 3;
  401. uint8_t g11 = ((I1[x*step + step+1] & 0x7) << 3 | I1[x*step + step+0] >> 5) << 2;
  402. uint8_t r11 = I1[x*step + step+1] & (~0x7);
  403. //Calculate 4 Y elements.
  404. uint8_t y00 = Rgb2Y(r00, g00, b00);
  405. uint8_t y01 = Rgb2Y(r01, g01, b01);
  406. uint8_t y10 = Rgb2Y(r10, g10, b10);
  407. uint8_t y11 = Rgb2Y(r11, g11, b11);
  408. //Calculate 4 U elements.
  409. uint8_t u00 = Rgb2U(r00, g00, b00);
  410. uint8_t u01 = Rgb2U(r01, g01, b01);
  411. uint8_t u10 = Rgb2U(r10, g10, b10);
  412. uint8_t u11 = Rgb2U(r11, g11, b11);
  413. //Calculate 4 V elements.
  414. uint8_t v00 = Rgb2V(r00, g00, b00);
  415. uint8_t v01 = Rgb2V(r01, g01, b01);
  416. uint8_t v10 = Rgb2V(r10, g10, b10);
  417. uint8_t v11 = Rgb2V(r11, g11, b11);
  418. //Calculate destination U element: average of 2x2 "original" U elements.
  419. uint8_t u0 = (u00 + u01 + u10 + u11)/4;
  420. //Calculate destination V element: average of 2x2 "original" V elements.
  421. uint8_t v0 = (v00 + v01 + v10 + v11)/4;
  422. //Store 4 Y elements (two in first row and two in second row).
  423. Y0[x + 0] = y00;
  424. Y0[x + 1] = y01;
  425. Y1[x + 0] = y10;
  426. Y1[x + 1] = y11;
  427. // //Store destination U element.
  428. UV0[x + 0] = u0;
  429. // //Store destination V element (next to stored U element).
  430. UV0[x + 1] = v0;
  431. }
  432. }
  433. //Convert image I from pixel ordered RGB to NV12 format.
  434. //I - Input image in pixel ordered RGB format
  435. //image_width - Number of columns of I
  436. //image_height - Number of rows of I
  437. //J - Destination "image" in NV12 format.
  438. //I is pixel ordered RGB color format (size in bytes is image_width*image_height*3):
  439. //RGBRGBRGBRGBRGBRGB
  440. //RGBRGBRGBRGBRGBRGB
  441. //RGBRGBRGBRGBRGBRGB
  442. //RGBRGBRGBRGBRGBRGB
  443. //
  444. //J is in NV12 format (size in bytes is image_width*image_height*3/2):
  445. //YYYYYY
  446. //YYYYYY
  447. //UVUVUV
  448. //Each element of destination U is average of 2x2 "original" U elements
  449. //Each element of destination V is average of 2x2 "original" V elements
  450. //
  451. //Limitations:
  452. //1. image_width must be a multiple of 2.
  453. //2. image_height must be a multiple of 2.
  454. //3. I and J must be two separate arrays (in place computation is not supported).
  455. void Rgb2NV12(const uint8_t I[], int step,
  456. const int image_width,
  457. const int image_height,
  458. uint8_t J[])
  459. {
  460. //In NV12 format, UV plane starts below Y plane.
  461. // uint8_t *UV = &J[image_width*image_height];
  462. uint8_t *UV = J;
  463. //I0 and I1 points two sequential source rows.
  464. const uint8_t *I0; //I0 -> rgbrgbrgbrgbrgbrgb...
  465. const uint8_t *I1; //I1 -> rgbrgbrgbrgbrgbrgb...
  466. //Y0 and Y1 points two sequential destination rows of Y plane.
  467. uint8_t *Y0; //Y0 -> yyyyyy
  468. uint8_t *Y1; //Y1 -> yyyyyy
  469. //UV0 points destination rows of interleaved UV plane.
  470. uint8_t *UV0; //UV0 -> uvuvuv
  471. int y; //Row index
  472. int width, height;
  473. int x_offset, y_offset;
  474. width = image_width > g_screen_width ? g_screen_width : image_width;
  475. height = image_height > g_screen_height ? g_screen_height : image_height;
  476. x_offset = (g_screen_width - width) / 2;
  477. y_offset = (g_screen_height - height) / 2;
  478. //In each iteration: process two rows of Y plane, and one row of interleaved UV plane.
  479. for (y = 0; y < height; y += 2)
  480. {
  481. I0 = &I[y*image_width*step]; //Input row width is image_width*3 bytes (each pixel is R,G,B).
  482. I1 = &I[(y+1)*image_width*step];
  483. Y0 = &J[(y+y_offset)*g_screen_width+x_offset]; //Output Y row width is image_width bytes (one Y element per pixel).
  484. Y1 = &J[(y+1+y_offset)*g_screen_width+x_offset];
  485. UV0 = &UV[g_screen_width*g_screen_height+((y+y_offset)/2*g_screen_width/2+x_offset/2)*2]; //Output UV row - width is same as Y row width.
  486. //Process two source rows into: Two Y destination row, and one destination interleaved U,V row.
  487. Rgb2NV12TwoRows(I0,
  488. I1,
  489. step,
  490. width,
  491. Y0,
  492. Y1,
  493. UV0);
  494. }
  495. }
  496. int convert_rgb565_to_nv12(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int is_nv21)
  497. {
  498. uint8_t *tmp = malloc(g_screen_size);
  499. uint32_t start_timems;
  500. uint32_t end_timems;
  501. struct timespec ts_start, ts_end;
  502. clock_gettime(CLOCK_MONOTONIC, &ts_start);
  503. Rgb2NV12(inBuf, 2, imgWidth, imgHeight, tmp);
  504. clock_gettime(CLOCK_MONOTONIC, &ts_end);
  505. start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000;
  506. end_timems = ts_end.tv_sec * 1000 + ts_end.tv_nsec/1000000;
  507. // printf("%s: convert use %dms\n", __func__, end_timems - start_timems);
  508. clock_gettime(CLOCK_MONOTONIC, &ts_start);
  509. memcpy(outBuf, tmp, g_screen_size);
  510. clock_gettime(CLOCK_MONOTONIC, &ts_end);
  511. start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000;
  512. end_timems = ts_end.tv_sec * 1000 + ts_end.tv_nsec/1000000;
  513. // printf("%s: use %dms\n", __func__, end_timems - start_timems);
  514. free(tmp);
  515. return 0;
  516. }
  517. int convert_yuyv_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod)
  518. {
  519. int rows ,cols;
  520. int y, u, v, r, g, b;
  521. const uint8_t *YUVdata;
  522. uint8_t *RGBdata;
  523. int Ypos, Upos, Vpos;
  524. uint32_t i = 0;
  525. int width, height;
  526. int x_offset, y_offset;
  527. uint8_t *tmp = malloc(g_screen_size);
  528. uint32_t start_timems;
  529. uint32_t end_timems;
  530. struct timespec ts_start, ts_end;
  531. clock_gettime(CLOCK_MONOTONIC, &ts_start);
  532. width = imgWidth > g_screen_width ? g_screen_width : imgWidth;
  533. height = imgHeight > g_screen_height ? g_screen_height : imgHeight;
  534. x_offset = (g_screen_width - width) / 2;
  535. y_offset = (g_screen_height - height) / 2;
  536. YUVdata = inBuf;
  537. RGBdata = tmp;
  538. /* two bytes for every pixels */
  539. for(rows = 0; rows < height; rows++)
  540. {
  541. // g_screen_width, g_screen_height g_screen_bpp
  542. RGBdata = tmp + ((rows + y_offset) * g_screen_width + x_offset) * g_screen_bpp / 8;
  543. Ypos = rows * imgWidth * 2;
  544. Upos = Ypos + 1;
  545. Vpos = Upos + 2;
  546. i = 0;
  547. for(cols = 0; cols < width; cols++)
  548. {
  549. y = YUVdata[Ypos];
  550. u = YUVdata[Upos] - 128;
  551. v = YUVdata[Vpos] - 128;
  552. r = y + v + ((v * 103) >> 8);
  553. g = y - ((u * 88) >> 8) - ((v * 183) >> 8);
  554. b = y + u + ((u * 198) >> 8);
  555. r = r > 255 ? 255 : (r < 0 ? 0 : r);
  556. g = g > 255 ? 255 : (g < 0 ? 0 : g);
  557. b = b > 255 ? 255 : (b < 0 ? 0 : b);
  558. /* low -> high r g b */
  559. if (g_screen_bpp == 16) { // RGB565
  560. *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g low 5bits,b high 5bits */
  561. *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r high 5bits, g high 3bits */
  562. } else if (g_screen_bpp == 24) { // RGB888
  563. *(RGBdata ++) = b;
  564. *(RGBdata ++) = g;
  565. *(RGBdata ++) = r;
  566. } else { // RGB8888
  567. *(RGBdata ++) = b;
  568. *(RGBdata ++) = g;
  569. *(RGBdata ++) = r;
  570. *(RGBdata ++) = 0xFF;
  571. }
  572. /* two bytes contain 1 y */
  573. Ypos += 2;
  574. //Ypos++;
  575. i++;
  576. /* every 2 y to update 1 uv */
  577. if(!(i & 0x01))
  578. {
  579. Upos = Ypos + 1;
  580. Vpos = Upos + 2;
  581. }
  582. }
  583. }
  584. clock_gettime(CLOCK_MONOTONIC, &ts_end);
  585. start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000;
  586. end_timems = ts_end.tv_sec * 1000 + ts_end.tv_nsec/1000000;
  587. // printf("%s: convert use %dms\n", __func__, end_timems - start_timems);
  588. clock_gettime(CLOCK_MONOTONIC, &ts_start);
  589. memcpy(outBuf, tmp, g_screen_size);
  590. clock_gettime(CLOCK_MONOTONIC, &ts_end);
  591. start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000;
  592. end_timems = ts_end.tv_sec * 1000 + ts_end.tv_nsec/1000000;
  593. // printf("%s: use %dms\n", __func__, end_timems - start_timems);
  594. free(tmp);
  595. return 0;
  596. }
  597. int convert_yuv444_to_rgb(uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod)
  598. {
  599. int rows ,cols;
  600. int y, u, v, r, g, b;
  601. uint8_t *YUVdata, *RGBdata;
  602. int Ypos;
  603. uint8_t *tmp = malloc(g_screen_size);
  604. YUVdata = inBuf;
  605. RGBdata = tmp;
  606. /* YUV */
  607. Ypos = 0;
  608. for(rows = 0; rows < imgHeight; rows++)
  609. {
  610. for(cols = 0; cols < imgWidth; cols++)
  611. {
  612. y = YUVdata[Ypos];
  613. u = YUVdata[Ypos + 1] - 128;
  614. v = YUVdata[Ypos + 2] - 128;
  615. r = y + v + ((v * 103) >> 8);
  616. g = y - ((u * 88) >> 8) - ((v * 183) >> 8);
  617. b = y + u + ((u * 198) >> 8);
  618. r = r > 255 ? 255 : (r < 0 ? 0 : r);
  619. g = g > 255 ? 255 : (g < 0 ? 0 : g);
  620. b = b > 255 ? 255 : (b < 0 ? 0 : b);
  621. /* low -> high r g b */
  622. if (g_screen_bpp == 16) { // RGB565
  623. *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g low 5bits,b high 5bits */
  624. *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r high 5bits,g high 3bits */
  625. } else if (g_screen_bpp == 24) { // RGB888
  626. *(RGBdata ++) = b;
  627. *(RGBdata ++) = g;
  628. *(RGBdata ++) = r;
  629. } else { // RGB8888
  630. *(RGBdata ++) = b;
  631. *(RGBdata ++) = g;
  632. *(RGBdata ++) = r;
  633. *(RGBdata ++) = 0xFF;
  634. }
  635. Ypos += 3;
  636. }
  637. }
  638. memcpy(outBuf, tmp, g_screen_size);
  639. free(tmp);
  640. return 0;
  641. }
  642. int convert_rgb565_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod)
  643. {
  644. int rows ,cols;
  645. const uint8_t *RGB565data;
  646. uint8_t *RGBdata;
  647. int RGBpos;
  648. int width, height;
  649. int x_offset, y_offset;
  650. uint8_t *tmp = malloc(g_screen_size);
  651. width = imgWidth > g_screen_width ? g_screen_width : imgWidth;
  652. height = imgHeight > g_screen_height ? g_screen_height : imgHeight;
  653. x_offset = (g_screen_width - width) / 2;
  654. y_offset = (g_screen_height - height) / 2;
  655. RGB565data = inBuf;
  656. RGBdata = tmp;
  657. if (imgWidth == g_screen_width) {
  658. RGBpos = (y_offset * g_screen_width + x_offset) * 2;
  659. memcpy(&tmp[RGBpos], inBuf, imgWidth * height * 2);
  660. memcpy(&outBuf[RGBpos], &tmp[RGBpos], imgWidth * height * 2);
  661. // memcpy(&outBuf[RGBpos], inBuf, imgWidth * height * 2);
  662. free(tmp);
  663. return 0;
  664. }
  665. RGBpos = 0;
  666. for(rows = 0; rows < imgHeight; rows++)
  667. {
  668. RGBdata = tmp + ((rows + y_offset) * g_screen_width + x_offset) * g_screen_bpp / 8;
  669. RGBpos = rows * imgWidth * 2;
  670. if (g_screen_bpp == 16) { // RGB565
  671. memcpy(RGBdata, &RGB565data[RGBpos], imgWidth * 2);
  672. } else {
  673. for(cols = 0; cols < imgWidth; cols++)
  674. {
  675. *(RGBdata ++) = RGB565data[RGBpos] & 0x1F;
  676. *(RGBdata ++) = (RGB565data[RGBpos + 1] & 0x7) << 3 | RGB565data[RGBpos] >> 5;
  677. *(RGBdata ++) = RGB565data[RGBpos + 1] >> 3;
  678. if (g_screen_bpp == 32) { // RGB888
  679. *(RGBdata ++) = 0xFF;
  680. }
  681. RGBpos += 2;
  682. }
  683. }
  684. }
  685. memcpy(outBuf, tmp, g_screen_size);
  686. free(tmp);
  687. return 0;
  688. }
  689. int convert_rgb888_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod)
  690. {
  691. int rows ,cols;
  692. const uint8_t *RGB888data;
  693. uint8_t *RGBdata;
  694. int RGBpos;
  695. int width, height;
  696. int x_offset, y_offset;
  697. uint8_t *tmp = malloc(g_screen_size);
  698. uint8_t r, g, b;
  699. width = imgWidth > g_screen_width ? g_screen_width : imgWidth;
  700. height = imgHeight > g_screen_height ? g_screen_height : imgHeight;
  701. x_offset = (g_screen_width - width) / 2;
  702. y_offset = (g_screen_height - height) / 2;
  703. RGB888data = inBuf;
  704. RGBdata = tmp;
  705. RGBpos = 0;
  706. for(rows = 0; rows < imgHeight; rows++)
  707. {
  708. RGBdata = tmp + ((rows + y_offset) * g_screen_width + x_offset) * g_screen_bpp / 8;
  709. RGBpos = rows * imgWidth * 3;
  710. if (g_screen_bpp == 24) { // RGB888
  711. memcpy(RGBdata, &RGB888data[RGBpos], imgWidth * 3);
  712. } else {
  713. for(cols = 0; cols < imgWidth; cols++)
  714. {
  715. if (g_screen_bpp == 16) { // RGB565
  716. b = RGB888data[RGBpos];
  717. g = RGB888data[RGBpos + 1];
  718. r = RGB888data[RGBpos + 2];
  719. *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g low 5bits,b high 5bits */
  720. *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r high 5bits,g high 3bits */
  721. } else { // RGB8888
  722. *(RGBdata ++) = RGB888data[RGBpos];
  723. *(RGBdata ++) = RGB888data[RGBpos + 1];
  724. *(RGBdata ++) = RGB888data[RGBpos + 2];
  725. *(RGBdata ++) = 0xFF;
  726. }
  727. RGBpos += 3;
  728. }
  729. }
  730. }
  731. memcpy(outBuf, tmp, g_screen_size);
  732. free(tmp);
  733. return 0;
  734. }