convert.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139
  1. /*------------------------------------------------------------------------
  2. * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
  3. *
  4. * This file is part of the ZBar Bar Code Reader.
  5. *
  6. * The ZBar Bar Code Reader is free software; you can redistribute it
  7. * and/or modify it under the terms of the GNU Lesser Public License as
  8. * published by the Free Software Foundation; either version 2.1 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * The ZBar Bar Code Reader is distributed in the hope that it will be
  12. * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  13. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser Public License
  17. * along with the ZBar Bar Code Reader; if not, write to the Free
  18. * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
  19. * Boston, MA 02110-1301 USA
  20. *
  21. * http://sourceforge.net/projects/zbar
  22. *------------------------------------------------------------------------*/
  23. #include "image.h"
  24. #include "video.h"
  25. #include "window.h"
  26. //#define stderr 1
  27. //#define fprintf(err, format, ...) printf(format, ...)
  28. /* pack bit size and location offset of a component into one byte
  29. */
  30. #define RGB_BITS(off, size) ((((8 - (size)) & 0x7) << 5) | ((off) & 0x1f))
  31. typedef void (conversion_handler_t)(zbar_image_t*,
  32. const zbar_format_def_t*,
  33. const zbar_image_t*,
  34. const zbar_format_def_t*);
  35. typedef struct conversion_def_s {
  36. int cost; /* conversion "badness" */
  37. conversion_handler_t *func; /* function that accomplishes it */
  38. } conversion_def_t;
  39. /* NULL terminated list of known formats, in order of preference
  40. * (NB Cr=V Cb=U)
  41. */
  42. const uint32_t _zbar_formats[] = {
  43. /* planar YUV formats */
  44. fourcc('4','2','2','P'), /* FIXME also YV16? */
  45. fourcc('I','4','2','0'),
  46. fourcc('Y','U','1','2'), /* FIXME also IYUV? */
  47. fourcc('Y','V','1','2'),
  48. fourcc('4','1','1','P'),
  49. /* planar Y + packed UV plane */
  50. fourcc('N','V','1','2'),
  51. fourcc('N','V','2','1'),
  52. /* packed YUV formats */
  53. fourcc('Y','U','Y','V'),
  54. fourcc('U','Y','V','Y'),
  55. fourcc('Y','U','Y','2'), /* FIXME add YVYU */
  56. fourcc('Y','U','V','4'), /* FIXME where is this from? */
  57. /* packed rgb formats */
  58. fourcc('R','G','B','3'),
  59. fourcc( 3 , 0 , 0 , 0 ),
  60. fourcc('B','G','R','3'),
  61. fourcc('R','G','B','4'),
  62. fourcc('B','G','R','4'),
  63. fourcc('R','G','B','P'),
  64. fourcc('R','G','B','O'),
  65. fourcc('R','G','B','R'),
  66. fourcc('R','G','B','Q'),
  67. fourcc('Y','U','V','9'),
  68. fourcc('Y','V','U','9'),
  69. /* basic grayscale format */
  70. fourcc('G','R','E','Y'),
  71. fourcc('Y','8','0','0'),
  72. fourcc('Y','8',' ',' '),
  73. fourcc('Y','8', 0 , 0 ),
  74. /* low quality RGB formats */
  75. fourcc('R','G','B','1'),
  76. fourcc('R','4','4','4'),
  77. fourcc('B','A','8','1'),
  78. /* unsupported packed YUV formats */
  79. fourcc('Y','4','1','P'),
  80. fourcc('Y','4','4','4'),
  81. fourcc('Y','U','V','O'),
  82. fourcc('H','M','1','2'),
  83. /* unsupported packed RGB format */
  84. fourcc('H','I','2','4'),
  85. /* unsupported compressed formats */
  86. fourcc('J','P','E','G'),
  87. fourcc('M','J','P','G'),
  88. fourcc('M','P','E','G'),
  89. /* terminator */
  90. 0
  91. };
  92. const int _zbar_num_formats = sizeof(_zbar_formats) / sizeof(uint32_t);
  93. /* format definitions */
  94. static const zbar_format_def_t format_defs[] = {
  95. { fourcc('R','G','B','4'), ZBAR_FMT_RGB_PACKED,
  96. { { 4, RGB_BITS(8, 8), RGB_BITS(16, 8), RGB_BITS(24, 8) } } },
  97. { fourcc('B','G','R','1'), ZBAR_FMT_RGB_PACKED,
  98. { { 1, RGB_BITS(0, 3), RGB_BITS(3, 3), RGB_BITS(6, 2) } } },
  99. { fourcc('4','2','2','P'), ZBAR_FMT_YUV_PLANAR, { { 1, 0, 0 /*UV*/ } } },
  100. { fourcc('Y','8','0','0'), ZBAR_FMT_GRAY, },
  101. { fourcc('Y','U','Y','2'), ZBAR_FMT_YUV_PACKED,
  102. { { 1, 0, 0, /*YUYV*/ } } },
  103. { fourcc('J','P','E','G'), ZBAR_FMT_JPEG, },
  104. { fourcc('Y','V','Y','U'), ZBAR_FMT_YUV_PACKED,
  105. { { 1, 0, 1, /*YVYU*/ } } },
  106. { fourcc('Y','8', 0 , 0 ), ZBAR_FMT_GRAY, },
  107. { fourcc('N','V','2','1'), ZBAR_FMT_YUV_NV, { { 1, 1, 1 /*VU*/ } } },
  108. { fourcc('N','V','1','2'), ZBAR_FMT_YUV_NV, { { 1, 1, 0 /*UV*/ } } },
  109. { fourcc('B','G','R','3'), ZBAR_FMT_RGB_PACKED,
  110. { { 3, RGB_BITS(16, 8), RGB_BITS(8, 8), RGB_BITS(0, 8) } } },
  111. { fourcc('Y','V','U','9'), ZBAR_FMT_YUV_PLANAR, { { 2, 2, 1 /*VU*/ } } },
  112. { fourcc('R','G','B','O'), ZBAR_FMT_RGB_PACKED,
  113. { { 2, RGB_BITS(10, 5), RGB_BITS(5, 5), RGB_BITS(0, 5) } } },
  114. { fourcc('R','G','B','Q'), ZBAR_FMT_RGB_PACKED,
  115. { { 2, RGB_BITS(2, 5), RGB_BITS(13, 5), RGB_BITS(8, 5) } } },
  116. { fourcc('G','R','E','Y'), ZBAR_FMT_GRAY, },
  117. { fourcc( 3 , 0 , 0 , 0 ), ZBAR_FMT_RGB_PACKED,
  118. { { 4, RGB_BITS(16, 8), RGB_BITS(8, 8), RGB_BITS(0, 8) } } },
  119. { fourcc('Y','8',' ',' '), ZBAR_FMT_GRAY, },
  120. { fourcc('I','4','2','0'), ZBAR_FMT_YUV_PLANAR, { { 1, 1, 0 /*UV*/ } } },
  121. { fourcc('R','G','B','1'), ZBAR_FMT_RGB_PACKED,
  122. { { 1, RGB_BITS(5, 3), RGB_BITS(2, 3), RGB_BITS(0, 2) } } },
  123. { fourcc('Y','U','1','2'), ZBAR_FMT_YUV_PLANAR, { { 1, 1, 0 /*UV*/ } } },
  124. { fourcc('Y','V','1','2'), ZBAR_FMT_YUV_PLANAR, { { 1, 1, 1 /*VU*/ } } },
  125. { fourcc('R','G','B','3'), ZBAR_FMT_RGB_PACKED,
  126. { { 3, RGB_BITS(0, 8), RGB_BITS(8, 8), RGB_BITS(16, 8) } } },
  127. { fourcc('R','4','4','4'), ZBAR_FMT_RGB_PACKED,
  128. { { 2, RGB_BITS(8, 4), RGB_BITS(4, 4), RGB_BITS(0, 4) } } },
  129. { fourcc('B','G','R','4'), ZBAR_FMT_RGB_PACKED,
  130. { { 4, RGB_BITS(16, 8), RGB_BITS(8, 8), RGB_BITS(0, 8) } } },
  131. { fourcc('Y','U','V','9'), ZBAR_FMT_YUV_PLANAR, { { 2, 2, 0 /*UV*/ } } },
  132. { fourcc('M','J','P','G'), ZBAR_FMT_JPEG, },
  133. { fourcc('4','1','1','P'), ZBAR_FMT_YUV_PLANAR, { { 2, 0, 0 /*UV*/ } } },
  134. { fourcc('R','G','B','P'), ZBAR_FMT_RGB_PACKED,
  135. { { 2, RGB_BITS(11, 5), RGB_BITS(5, 6), RGB_BITS(0, 5) } } },
  136. { fourcc('R','G','B','R'), ZBAR_FMT_RGB_PACKED,
  137. { { 2, RGB_BITS(3, 5), RGB_BITS(13, 6), RGB_BITS(8, 5) } } },
  138. { fourcc('Y','U','Y','V'), ZBAR_FMT_YUV_PACKED,
  139. { { 1, 0, 0, /*YUYV*/ } } },
  140. { fourcc('U','Y','V','Y'), ZBAR_FMT_YUV_PACKED,
  141. { { 1, 0, 2, /*UYVY*/ } } },
  142. };
  143. static const int num_format_defs =
  144. sizeof(format_defs) / sizeof(zbar_format_def_t);
  145. #ifdef DEBUG_CONVERT
  146. static int intsort (const void *a,
  147. const void *b)
  148. {
  149. return(*(uint32_t*)a - *(uint32_t*)b);
  150. }
  151. #endif
  152. /* verify that format list is in required sort order */
  153. static inline int verify_format_sort (void)
  154. {
  155. int i;
  156. for(i = 0; i < num_format_defs; i++) {
  157. int j = i * 2 + 1;
  158. if((j < num_format_defs &&
  159. format_defs[i].format < format_defs[j].format) ||
  160. (j + 1 < num_format_defs &&
  161. format_defs[j + 1].format < format_defs[i].format))
  162. break;
  163. }
  164. if(i == num_format_defs)
  165. return(0);
  166. /* spew correct order for fix */
  167. //fprintf(stderr, "ERROR: image format list is not sorted!?\n");
  168. #ifdef DEBUG_CONVERT
  169. assert(num_format_defs);
  170. uint32_t sorted[num_format_defs];
  171. uint32_t ordered[num_format_defs];
  172. for(i = 0; i < num_format_defs; i++)
  173. sorted[i] = format_defs[i].format;
  174. qsort(sorted, num_format_defs, sizeof(uint32_t), intsort);
  175. for(i = 0; i < num_format_defs; i = i << 1 | 1);
  176. i = (i - 1) / 2;
  177. ordered[i] = sorted[0];
  178. int j, k;
  179. for(j = 1; j < num_format_defs; j++) {
  180. k = i * 2 + 2;
  181. if(k < num_format_defs) {
  182. i = k;
  183. for(k = k * 2 + 1; k < num_format_defs; k = k * 2 + 1)
  184. i = k;
  185. }
  186. else {
  187. for(k = (i - 1) / 2; i != k * 2 + 1; k = (i - 1) / 2) {
  188. assert(i);
  189. i = k;
  190. }
  191. i = k;
  192. }
  193. ordered[i] = sorted[j];
  194. }
  195. #if 0
  196. fprintf(stderr, "correct sort order is:");
  197. for(i = 0; i < num_format_defs; i++)
  198. fprintf(stderr, " %4.4s", (char*)&ordered[i]);
  199. fprintf(stderr, "\n");
  200. #endif
  201. #endif
  202. return(-1);
  203. }
  204. static inline void uv_round (zbar_image_t *img,
  205. const zbar_format_def_t *fmt)
  206. {
  207. img->width >>= fmt->p.yuv.xsub2;
  208. img->width <<= fmt->p.yuv.xsub2;
  209. img->height >>= fmt->p.yuv.ysub2;
  210. img->height <<= fmt->p.yuv.ysub2;
  211. }
  212. static inline void uv_roundup (zbar_image_t *img,
  213. const zbar_format_def_t *fmt)
  214. {
  215. if(fmt->group == ZBAR_FMT_GRAY)
  216. return;
  217. unsigned xmask = (1 << fmt->p.yuv.xsub2) - 1;
  218. if(img->width & xmask)
  219. img->width = (img->width + xmask) & ~xmask;
  220. unsigned ymask = (1 << fmt->p.yuv.ysub2) - 1;
  221. if(img->height & ymask)
  222. img->height = (img->height + ymask) & ~ymask;
  223. }
  224. static inline unsigned long uvp_size (const zbar_image_t *img,
  225. const zbar_format_def_t *fmt)
  226. {
  227. if(fmt->group == ZBAR_FMT_GRAY)
  228. return(0);
  229. return((img->width >> fmt->p.yuv.xsub2) *
  230. (img->height >> fmt->p.yuv.ysub2));
  231. }
  232. static inline uint32_t convert_read_rgb (const uint8_t *srcp,
  233. int bpp)
  234. {
  235. uint32_t p;
  236. if(bpp == 3) {
  237. p = *srcp;
  238. p |= *(srcp + 1) << 8;
  239. p |= *(srcp + 2) << 16;
  240. }
  241. else if(bpp == 4)
  242. p = *((uint32_t*)(srcp));
  243. else if(bpp == 2)
  244. p = *((uint16_t*)(srcp));
  245. else
  246. p = *srcp;
  247. return(p);
  248. }
  249. static inline void convert_write_rgb (uint8_t *dstp,
  250. uint32_t p,
  251. int bpp)
  252. {
  253. if(bpp == 3) {
  254. *dstp = p & 0xff;
  255. *(dstp + 1) = (p >> 8) & 0xff;
  256. *(dstp + 2) = (p >> 16) & 0xff;
  257. }
  258. else if(bpp == 4)
  259. *((uint32_t*)dstp) = p;
  260. else if(bpp == 2)
  261. *((uint16_t*)dstp) = p;
  262. else
  263. *dstp = p;
  264. }
  265. /* cleanup linked image by unrefing */
  266. static void cleanup_ref (zbar_image_t *img)
  267. {
  268. if(img->next)
  269. _zbar_image_refcnt(img->next, -1);
  270. }
  271. /* resize y plane, drop extra columns/rows from the right/bottom,
  272. * or duplicate last column/row to pad missing data
  273. */
  274. static inline void convert_y_resize (zbar_image_t *dst,
  275. const zbar_format_def_t *dstfmt,
  276. const zbar_image_t *src,
  277. const zbar_format_def_t *srcfmt,
  278. size_t n)
  279. {
  280. if(dst->width == src->width && dst->height == src->height) {
  281. memcpy((void*)dst->data, src->data, n);
  282. return;
  283. }
  284. uint8_t *psrc = (void*)src->data;
  285. uint8_t *pdst = (void*)dst->data;
  286. unsigned width = (dst->width > src->width) ? src->width : dst->width;
  287. unsigned xpad = (dst->width > src->width) ? dst->width - src->width : 0;
  288. unsigned height = (dst->height > src->height) ? src->height : dst->height;
  289. unsigned y;
  290. for(y = 0; y < height; y++) {
  291. memcpy(pdst, psrc, width);
  292. pdst += width;
  293. psrc += src->width;
  294. if(xpad) {
  295. memset(pdst, *(psrc - 1), xpad);
  296. pdst += xpad;
  297. }
  298. }
  299. psrc -= src->width;
  300. for(; y < dst->height; y++) {
  301. memcpy(pdst, psrc, width);
  302. pdst += width;
  303. if(xpad) {
  304. memset(pdst, *(psrc - 1), xpad);
  305. pdst += xpad;
  306. }
  307. }
  308. }
  309. /* make new image w/reference to the same image data */
  310. static void convert_copy (zbar_image_t *dst,
  311. const zbar_format_def_t *dstfmt,
  312. const zbar_image_t *src,
  313. const zbar_format_def_t *srcfmt)
  314. {
  315. if(src->width == dst->width &&
  316. src->height == dst->height) {
  317. dst->data = src->data;
  318. dst->datalen = src->datalen;
  319. dst->cleanup = cleanup_ref;
  320. zbar_image_t *s = (zbar_image_t*)src;
  321. dst->next = s;
  322. _zbar_image_refcnt(s, 1);
  323. }
  324. else
  325. /* NB only for GRAY/YUV_PLANAR formats */
  326. convert_y_resize(dst, dstfmt, src, srcfmt, dst->width * dst->height);
  327. }
  328. /* append neutral UV plane to grayscale image */
  329. static void convert_uvp_append (zbar_image_t *dst,
  330. const zbar_format_def_t *dstfmt,
  331. const zbar_image_t *src,
  332. const zbar_format_def_t *srcfmt)
  333. {
  334. uv_roundup(dst, dstfmt);
  335. dst->datalen = uvp_size(dst, dstfmt) * 2;
  336. unsigned long n = dst->width * dst->height;
  337. dst->datalen += n;
  338. assert(src->datalen >= src->width * src->height);
  339. zprintf(24, "dst=%dx%d (%lx) %lx src=%dx%d %lx\n",
  340. dst->width, dst->height, n, dst->datalen,
  341. src->width, src->height, src->datalen);
  342. dst->data = malloc(dst->datalen);
  343. if(!dst->data) return;
  344. convert_y_resize(dst, dstfmt, src, srcfmt, n);
  345. memset((unsigned int)dst->data + n, 0x80, dst->datalen - n);
  346. }
  347. /* interleave YUV planes into packed YUV */
  348. static void convert_yuv_pack (zbar_image_t *dst,
  349. const zbar_format_def_t *dstfmt,
  350. const zbar_image_t *src,
  351. const zbar_format_def_t *srcfmt)
  352. {
  353. uv_roundup(dst, dstfmt);
  354. dst->datalen = dst->width * dst->height + uvp_size(dst, dstfmt) * 2;
  355. dst->data = malloc(dst->datalen);
  356. if(!dst->data) return;
  357. uint8_t *dstp = (void*)dst->data;
  358. unsigned long srcm = uvp_size(src, srcfmt);
  359. unsigned long srcn = src->width * src->height;
  360. assert(src->datalen >= srcn + 2 * srcn);
  361. uint8_t flags = dstfmt->p.yuv.packorder ^ srcfmt->p.yuv.packorder;
  362. uint8_t *srcy = (void*)src->data;
  363. const uint8_t *srcu, *srcv;
  364. if(flags & 1) {
  365. srcv = (unsigned int)src->data + srcn;
  366. srcu = srcv + srcm;
  367. } else {
  368. srcu = (unsigned int)src->data + srcn;
  369. srcv = srcu + srcm;
  370. }
  371. flags = dstfmt->p.yuv.packorder & 2;
  372. unsigned srcl = src->width >> srcfmt->p.yuv.xsub2;
  373. unsigned xmask = (1 << srcfmt->p.yuv.xsub2) - 1;
  374. unsigned ymask = (1 << srcfmt->p.yuv.ysub2) - 1;
  375. unsigned x, y;
  376. uint8_t y0 = 0, y1 = 0, u = 0x80, v = 0x80;
  377. for(y = 0; y < dst->height; y++) {
  378. if(y >= src->height) {
  379. srcy -= src->width;
  380. srcu -= srcl; srcv -= srcl;
  381. }
  382. else if(y & ymask) {
  383. srcu -= srcl; srcv -= srcl;
  384. }
  385. for(x = 0; x < dst->width; x += 2) {
  386. if(x < src->width) {
  387. y0 = *(srcy++); y1 = *(srcy++);
  388. if(!(x & xmask)) {
  389. u = *(srcu++); v = *(srcv++);
  390. }
  391. }
  392. if(flags) {
  393. *(dstp++) = u; *(dstp++) = y0;
  394. *(dstp++) = v; *(dstp++) = y1;
  395. } else {
  396. *(dstp++) = y0; *(dstp++) = u;
  397. *(dstp++) = y1; *(dstp++) = v;
  398. }
  399. }
  400. for(; x < src->width; x += 2) {
  401. srcy += 2;
  402. if(!(x & xmask)) {
  403. srcu++; srcv++;
  404. }
  405. }
  406. }
  407. }
  408. /* split packed YUV samples and join into YUV planes
  409. * FIXME currently ignores color and grayscales the image
  410. */
  411. static void convert_yuv_unpack (zbar_image_t *dst,
  412. const zbar_format_def_t *dstfmt,
  413. const zbar_image_t *src,
  414. const zbar_format_def_t *srcfmt)
  415. {
  416. uv_roundup(dst, dstfmt);
  417. unsigned long dstn = dst->width * dst->height;
  418. unsigned long dstm2 = uvp_size(dst, dstfmt) * 2;
  419. dst->datalen = dstn + dstm2;
  420. dst->data = malloc(dst->datalen);
  421. if(!dst->data) return;
  422. if(dstm2)
  423. memset((unsigned int)dst->data + dstn, 0x80, dstm2);
  424. uint8_t *dsty = (void*)dst->data;
  425. uint8_t flags = srcfmt->p.yuv.packorder ^ dstfmt->p.yuv.packorder;
  426. flags &= 2;
  427. const uint8_t *srcp = src->data;
  428. if(flags)
  429. srcp++;
  430. unsigned srcl = src->width + (src->width >> srcfmt->p.yuv.xsub2);
  431. unsigned x, y;
  432. uint8_t y0 = 0, y1 = 0;
  433. for(y = 0; y < dst->height; y++) {
  434. if(y >= src->height)
  435. srcp -= srcl;
  436. for(x = 0; x < dst->width; x += 2) {
  437. if(x < src->width) {
  438. y0 = *(srcp++); srcp++;
  439. y1 = *(srcp++); srcp++;
  440. }
  441. *(dsty++) = y0;
  442. *(dsty++) = y1;
  443. }
  444. if(x < src->width)
  445. srcp += (src->width - x) * 2;
  446. }
  447. }
  448. /* resample and resize UV plane(s)
  449. * FIXME currently ignores color and grayscales the image
  450. */
  451. static void convert_uvp_resample (zbar_image_t *dst,
  452. const zbar_format_def_t *dstfmt,
  453. const zbar_image_t *src,
  454. const zbar_format_def_t *srcfmt)
  455. {
  456. uv_roundup(dst, dstfmt);
  457. unsigned long dstn = dst->width * dst->height;
  458. unsigned long dstm2 = uvp_size(dst, dstfmt) * 2;
  459. dst->datalen = dstn + dstm2;
  460. dst->data = malloc(dst->datalen);
  461. if(!dst->data) return;
  462. convert_y_resize(dst, dstfmt, src, srcfmt, dstn);
  463. if(dstm2)
  464. memset((unsigned int)dst->data + dstn, 0x80, dstm2);
  465. }
  466. /* rearrange interleaved UV componets */
  467. static void convert_uv_resample (zbar_image_t *dst,
  468. const zbar_format_def_t *dstfmt,
  469. const zbar_image_t *src,
  470. const zbar_format_def_t *srcfmt)
  471. {
  472. uv_roundup(dst, dstfmt);
  473. unsigned long dstn = dst->width * dst->height;
  474. dst->datalen = dstn + uvp_size(dst, dstfmt) * 2;
  475. dst->data = malloc(dst->datalen);
  476. if(!dst->data) return;
  477. uint8_t *dstp = (void*)dst->data;
  478. uint8_t flags = (srcfmt->p.yuv.packorder ^ dstfmt->p.yuv.packorder) & 1;
  479. const uint8_t *srcp = src->data;
  480. unsigned srcl = src->width + (src->width >> srcfmt->p.yuv.xsub2);
  481. unsigned x, y;
  482. uint8_t y0 = 0, y1 = 0, u = 0x80, v = 0x80;
  483. for(y = 0; y < dst->height; y++) {
  484. if(y >= src->height)
  485. srcp -= srcl;
  486. for(x = 0; x < dst->width; x += 2) {
  487. if(x < src->width) {
  488. if(!(srcfmt->p.yuv.packorder & 2)) {
  489. y0 = *(srcp++); u = *(srcp++);
  490. y1 = *(srcp++); v = *(srcp++);
  491. }
  492. else {
  493. u = *(srcp++); y0 = *(srcp++);
  494. v = *(srcp++); y1 = *(srcp++);
  495. }
  496. if(flags) {
  497. uint8_t tmp = u; u = v; v = tmp;
  498. }
  499. }
  500. if(!(dstfmt->p.yuv.packorder & 2)) {
  501. *(dstp++) = y0; *(dstp++) = u;
  502. *(dstp++) = y1; *(dstp++) = v;
  503. }
  504. else {
  505. *(dstp++) = u; *(dstp++) = y0;
  506. *(dstp++) = v; *(dstp++) = y1;
  507. }
  508. }
  509. if(x < src->width)
  510. srcp += (src->width - x) * 2;
  511. }
  512. }
  513. /* YUV planes to packed RGB
  514. * FIXME currently ignores color and grayscales the image
  515. */
  516. static void convert_yuvp_to_rgb (zbar_image_t *dst,
  517. const zbar_format_def_t *dstfmt,
  518. const zbar_image_t *src,
  519. const zbar_format_def_t *srcfmt)
  520. {
  521. dst->datalen = dst->width * dst->height * dstfmt->p.rgb.bpp;
  522. dst->data = malloc(dst->datalen);
  523. if(!dst->data) return;
  524. uint8_t *dstp = (void*)dst->data;
  525. int drbits = RGB_SIZE(dstfmt->p.rgb.red);
  526. int drbit0 = RGB_OFFSET(dstfmt->p.rgb.red);
  527. int dgbits = RGB_SIZE(dstfmt->p.rgb.green);
  528. int dgbit0 = RGB_OFFSET(dstfmt->p.rgb.green);
  529. int dbbits = RGB_SIZE(dstfmt->p.rgb.blue);
  530. int dbbit0 = RGB_OFFSET(dstfmt->p.rgb.blue);
  531. unsigned long srcm = uvp_size(src, srcfmt);
  532. unsigned long srcn = src->width * src->height;
  533. assert(src->datalen >= srcn + 2 * srcm);
  534. uint8_t *srcy = (void*)src->data;
  535. unsigned x, y;
  536. uint32_t p = 0;
  537. for(y = 0; y < dst->height; y++) {
  538. if(y >= src->height)
  539. srcy -= src->width;
  540. for(x = 0; x < dst->width; x++) {
  541. if(x < src->width) {
  542. /* FIXME color space? */
  543. unsigned y0 = *(srcy++);
  544. p = (((y0 >> drbits) << drbit0) |
  545. ((y0 >> dgbits) << dgbit0) |
  546. ((y0 >> dbbits) << dbbit0));
  547. }
  548. convert_write_rgb(dstp, p, dstfmt->p.rgb.bpp);
  549. dstp += dstfmt->p.rgb.bpp;
  550. }
  551. if(x < src->width)
  552. srcy += (src->width - x);
  553. }
  554. }
  555. /* packed RGB to YUV planes
  556. * FIXME currently ignores color and grayscales the image
  557. */
  558. static void convert_rgb_to_yuvp (zbar_image_t *dst,
  559. const zbar_format_def_t *dstfmt,
  560. const zbar_image_t *src,
  561. const zbar_format_def_t *srcfmt)
  562. {
  563. uv_roundup(dst, dstfmt);
  564. unsigned long dstn = dst->width * dst->height;
  565. unsigned long dstm2 = uvp_size(dst, dstfmt) * 2;
  566. dst->datalen = dstn + dstm2;
  567. dst->data = malloc(dst->datalen);
  568. if(!dst->data) return;
  569. if(dstm2)
  570. memset((unsigned int)dst->data + dstn, 0x80, dstm2);
  571. uint8_t *dsty = (void*)dst->data;
  572. assert(src->datalen >= (src->width * src->height * srcfmt->p.rgb.bpp));
  573. const uint8_t *srcp = src->data;
  574. int rbits = RGB_SIZE(srcfmt->p.rgb.red);
  575. int rbit0 = RGB_OFFSET(srcfmt->p.rgb.red);
  576. int gbits = RGB_SIZE(srcfmt->p.rgb.green);
  577. int gbit0 = RGB_OFFSET(srcfmt->p.rgb.green);
  578. int bbits = RGB_SIZE(srcfmt->p.rgb.blue);
  579. int bbit0 = RGB_OFFSET(srcfmt->p.rgb.blue);
  580. unsigned srcl = src->width * srcfmt->p.rgb.bpp;
  581. unsigned x, y;
  582. uint16_t y0 = 0;
  583. for(y = 0; y < dst->height; y++) {
  584. if(y >= src->height)
  585. srcp -= srcl;
  586. for(x = 0; x < dst->width; x++) {
  587. if(x < src->width) {
  588. uint8_t r, g, b;
  589. uint32_t p = convert_read_rgb(srcp, srcfmt->p.rgb.bpp);
  590. srcp += srcfmt->p.rgb.bpp;
  591. /* FIXME endianness? */
  592. r = ((p >> rbit0) << rbits) & 0xff;
  593. g = ((p >> gbit0) << gbits) & 0xff;
  594. b = ((p >> bbit0) << bbits) & 0xff;
  595. /* FIXME color space? */
  596. y0 = ((77 * r + 150 * g + 29 * b) + 0x80) >> 8;
  597. }
  598. *(dsty++) = y0;
  599. }
  600. if(x < src->width)
  601. srcp += (src->width - x) * srcfmt->p.rgb.bpp;
  602. }
  603. }
  604. /* packed YUV to packed RGB */
  605. static void convert_yuv_to_rgb (zbar_image_t *dst,
  606. const zbar_format_def_t *dstfmt,
  607. const zbar_image_t *src,
  608. const zbar_format_def_t *srcfmt)
  609. {
  610. unsigned long dstn = dst->width * dst->height;
  611. dst->datalen = dstn * dstfmt->p.rgb.bpp;
  612. dst->data = malloc(dst->datalen);
  613. if(!dst->data) return;
  614. uint8_t *dstp = (void*)dst->data;
  615. int drbits = RGB_SIZE(dstfmt->p.rgb.red);
  616. int drbit0 = RGB_OFFSET(dstfmt->p.rgb.red);
  617. int dgbits = RGB_SIZE(dstfmt->p.rgb.green);
  618. int dgbit0 = RGB_OFFSET(dstfmt->p.rgb.green);
  619. int dbbits = RGB_SIZE(dstfmt->p.rgb.blue);
  620. int dbbit0 = RGB_OFFSET(dstfmt->p.rgb.blue);
  621. assert(src->datalen >= (src->width * src->height +
  622. uvp_size(src, srcfmt) * 2));
  623. const uint8_t *srcp = src->data;
  624. if(srcfmt->p.yuv.packorder & 2)
  625. srcp++;
  626. assert(srcfmt->p.yuv.xsub2 == 1);
  627. unsigned srcl = src->width + (src->width >> 1);
  628. unsigned x, y;
  629. uint32_t p = 0;
  630. for(y = 0; y < dst->height; y++) {
  631. if(y >= src->height)
  632. srcp -= srcl;
  633. for(x = 0; x < dst->width; x++) {
  634. if(x < src->width) {
  635. uint8_t y0 = *(srcp++);
  636. srcp++;
  637. if(y0 <= 16)
  638. y0 = 0;
  639. else if(y0 >= 235)
  640. y0 = 255;
  641. else
  642. y0 = (uint16_t)(y0 - 16) * 255 / 219;
  643. p = (((y0 >> drbits) << drbit0) |
  644. ((y0 >> dgbits) << dgbit0) |
  645. ((y0 >> dbbits) << dbbit0));
  646. }
  647. convert_write_rgb(dstp, p, dstfmt->p.rgb.bpp);
  648. dstp += dstfmt->p.rgb.bpp;
  649. }
  650. if(x < src->width)
  651. srcp += (src->width - x) * 2;
  652. }
  653. }
  654. /* packed RGB to packed YUV
  655. * FIXME currently ignores color and grayscales the image
  656. */
  657. static void convert_rgb_to_yuv (zbar_image_t *dst,
  658. const zbar_format_def_t *dstfmt,
  659. const zbar_image_t *src,
  660. const zbar_format_def_t *srcfmt)
  661. {
  662. uv_roundup(dst, dstfmt);
  663. dst->datalen = dst->width * dst->height + uvp_size(dst, dstfmt) * 2;
  664. dst->data = malloc(dst->datalen);
  665. if(!dst->data) return;
  666. uint8_t *dstp = (void*)dst->data;
  667. uint8_t flags = dstfmt->p.yuv.packorder & 2;
  668. assert(src->datalen >= (src->width * src->height * srcfmt->p.rgb.bpp));
  669. const uint8_t *srcp = src->data;
  670. int rbits = RGB_SIZE(srcfmt->p.rgb.red);
  671. int rbit0 = RGB_OFFSET(srcfmt->p.rgb.red);
  672. int gbits = RGB_SIZE(srcfmt->p.rgb.green);
  673. int gbit0 = RGB_OFFSET(srcfmt->p.rgb.green);
  674. int bbits = RGB_SIZE(srcfmt->p.rgb.blue);
  675. int bbit0 = RGB_OFFSET(srcfmt->p.rgb.blue);
  676. unsigned srcl = src->width * srcfmt->p.rgb.bpp;
  677. unsigned x, y;
  678. uint16_t y0 = 0;
  679. for(y = 0; y < dst->height; y++) {
  680. if(y >= src->height)
  681. srcp -= srcl;
  682. for(x = 0; x < dst->width; x++) {
  683. if(x < src->width) {
  684. uint8_t r, g, b;
  685. uint32_t p = convert_read_rgb(srcp, srcfmt->p.rgb.bpp);
  686. srcp += srcfmt->p.rgb.bpp;
  687. /* FIXME endianness? */
  688. r = ((p >> rbit0) << rbits) & 0xff;
  689. g = ((p >> gbit0) << gbits) & 0xff;
  690. b = ((p >> bbit0) << bbits) & 0xff;
  691. /* FIXME color space? */
  692. y0 = ((77 * r + 150 * g + 29 * b) + 0x80) >> 8;
  693. }
  694. if(flags) {
  695. *(dstp++) = 0x80; *(dstp++) = y0;
  696. }
  697. else {
  698. *(dstp++) = y0; *(dstp++) = 0x80;
  699. }
  700. }
  701. if(x < src->width)
  702. srcp += (src->width - x) * srcfmt->p.rgb.bpp;
  703. }
  704. }
  705. /* resample and resize packed RGB components */
  706. static void convert_rgb_resample (zbar_image_t *dst,
  707. const zbar_format_def_t *dstfmt,
  708. const zbar_image_t *src,
  709. const zbar_format_def_t *srcfmt)
  710. {
  711. unsigned long dstn = dst->width * dst->height;
  712. dst->datalen = dstn * dstfmt->p.rgb.bpp;
  713. dst->data = malloc(dst->datalen);
  714. if(!dst->data) return;
  715. uint8_t *dstp = (void*)dst->data;
  716. int drbits = RGB_SIZE(dstfmt->p.rgb.red);
  717. int drbit0 = RGB_OFFSET(dstfmt->p.rgb.red);
  718. int dgbits = RGB_SIZE(dstfmt->p.rgb.green);
  719. int dgbit0 = RGB_OFFSET(dstfmt->p.rgb.green);
  720. int dbbits = RGB_SIZE(dstfmt->p.rgb.blue);
  721. int dbbit0 = RGB_OFFSET(dstfmt->p.rgb.blue);
  722. assert(src->datalen >= (src->width * src->height * srcfmt->p.rgb.bpp));
  723. const uint8_t *srcp = src->data;
  724. int srbits = RGB_SIZE(srcfmt->p.rgb.red);
  725. int srbit0 = RGB_OFFSET(srcfmt->p.rgb.red);
  726. int sgbits = RGB_SIZE(srcfmt->p.rgb.green);
  727. int sgbit0 = RGB_OFFSET(srcfmt->p.rgb.green);
  728. int sbbits = RGB_SIZE(srcfmt->p.rgb.blue);
  729. int sbbit0 = RGB_OFFSET(srcfmt->p.rgb.blue);
  730. unsigned srcl = src->width * srcfmt->p.rgb.bpp;
  731. unsigned x, y;
  732. uint32_t p = 0;
  733. for(y = 0; y < dst->height; y++) {
  734. if(y >= src->height)
  735. y -= srcl;
  736. for(x = 0; x < dst->width; x++) {
  737. if(x < src->width) {
  738. uint8_t r, g, b;
  739. p = convert_read_rgb(srcp, srcfmt->p.rgb.bpp);
  740. srcp += srcfmt->p.rgb.bpp;
  741. /* FIXME endianness? */
  742. r = (p >> srbit0) << srbits;
  743. g = (p >> sgbit0) << sgbits;
  744. b = (p >> sbbit0) << sbbits;
  745. p = (((r >> drbits) << drbit0) |
  746. ((g >> dgbits) << dgbit0) |
  747. ((b >> dbbits) << dbbit0));
  748. }
  749. convert_write_rgb(dstp, p, dstfmt->p.rgb.bpp);
  750. dstp += dstfmt->p.rgb.bpp;
  751. }
  752. if(x < src->width)
  753. srcp += (src->width - x) * srcfmt->p.rgb.bpp;
  754. }
  755. }
  756. #ifdef HAVE_LIBJPEG
  757. void _zbar_convert_jpeg_to_y(zbar_image_t *dst,
  758. const zbar_format_def_t *dstfmt,
  759. const zbar_image_t *src,
  760. const zbar_format_def_t *srcfmt);
  761. static void convert_jpeg(zbar_image_t *dst,
  762. const zbar_format_def_t *dstfmt,
  763. const zbar_image_t *src,
  764. const zbar_format_def_t *srcfmt);
  765. #endif
  766. /* group conversion matrix */
  767. static conversion_def_t conversions[][ZBAR_FMT_NUM] = {
  768. { /* *from* GRAY */
  769. { 0, convert_copy }, /* to GRAY */
  770. { 8, convert_uvp_append }, /* to YUV_PLANAR */
  771. { 24, convert_yuv_pack }, /* to YUV_PACKED */
  772. { 32, convert_yuvp_to_rgb }, /* to RGB_PACKED */
  773. { 8, convert_uvp_append }, /* to YUV_NV */
  774. { -1, NULL }, /* to JPEG */
  775. },
  776. { /* from YUV_PLANAR */
  777. { 1, convert_copy }, /* to GRAY */
  778. { 48, convert_uvp_resample }, /* to YUV_PLANAR */
  779. { 64, convert_yuv_pack }, /* to YUV_PACKED */
  780. { 128, convert_yuvp_to_rgb }, /* to RGB_PACKED */
  781. { 40, convert_uvp_append }, /* to YUV_NV */
  782. { -1, NULL }, /* to JPEG */
  783. },
  784. { /* from YUV_PACKED */
  785. { 24, convert_yuv_unpack }, /* to GRAY */
  786. { 52, convert_yuv_unpack }, /* to YUV_PLANAR */
  787. { 20, convert_uv_resample }, /* to YUV_PACKED */
  788. { 144, convert_yuv_to_rgb }, /* to RGB_PACKED */
  789. { 18, convert_yuv_unpack }, /* to YUV_NV */
  790. { -1, NULL }, /* to JPEG */
  791. },
  792. { /* from RGB_PACKED */
  793. { 112, convert_rgb_to_yuvp }, /* to GRAY */
  794. { 160, convert_rgb_to_yuvp }, /* to YUV_PLANAR */
  795. { 144, convert_rgb_to_yuv }, /* to YUV_PACKED */
  796. { 120, convert_rgb_resample }, /* to RGB_PACKED */
  797. { 152, convert_rgb_to_yuvp }, /* to YUV_NV */
  798. { -1, NULL }, /* to JPEG */
  799. },
  800. { /* from YUV_NV (FIXME treated as GRAY) */
  801. { 1, convert_copy }, /* to GRAY */
  802. { 8, convert_uvp_append }, /* to YUV_PLANAR */
  803. { 24, convert_yuv_pack }, /* to YUV_PACKED */
  804. { 32, convert_yuvp_to_rgb }, /* to RGB_PACKED */
  805. { 8, convert_uvp_append }, /* to YUV_NV */
  806. { -1, NULL }, /* to JPEG */
  807. },
  808. #ifdef HAVE_LIBJPEG
  809. { /* from JPEG */
  810. { 96, _zbar_convert_jpeg_to_y }, /* to GRAY */
  811. { 104, convert_jpeg }, /* to YUV_PLANAR */
  812. { 116, convert_jpeg }, /* to YUV_PACKED */
  813. { 256, convert_jpeg }, /* to RGB_PACKED */
  814. { 104, convert_jpeg }, /* to YUV_NV */
  815. { -1, NULL }, /* to JPEG */
  816. },
  817. #else
  818. { /* from JPEG */
  819. { -1, NULL }, /* to GRAY */
  820. { -1, NULL }, /* to YUV_PLANAR */
  821. { -1, NULL }, /* to YUV_PACKED */
  822. { -1, NULL }, /* to RGB_PACKED */
  823. { -1, NULL }, /* to YUV_NV */
  824. { -1, NULL }, /* to JPEG */
  825. },
  826. #endif
  827. };
  828. const zbar_format_def_t *_zbar_format_lookup (uint32_t fmt)
  829. {
  830. const zbar_format_def_t *def = NULL;
  831. int i = 0;
  832. while(i < num_format_defs) {
  833. def = &format_defs[i];
  834. if(fmt == def->format)
  835. return(def);
  836. i = i * 2 + 1;
  837. if(fmt > def->format)
  838. i++;
  839. }
  840. return(NULL);
  841. }
  842. #ifdef HAVE_LIBJPEG
  843. /* convert JPEG data via an intermediate format supported by libjpeg */
  844. static void convert_jpeg (zbar_image_t *dst,
  845. const zbar_format_def_t *dstfmt,
  846. const zbar_image_t *src,
  847. const zbar_format_def_t *srcfmt)
  848. {
  849. /* define intermediate image in a format supported by libjpeg
  850. * (currently only grayscale)
  851. */
  852. zbar_image_t *tmp;
  853. if(!src->src) {
  854. tmp = zbar_image_create();
  855. tmp->format = fourcc('Y','8','0','0');
  856. tmp->width = dst->width;
  857. tmp->height = dst->height;
  858. }
  859. else {
  860. tmp = src->src->jpeg_img;
  861. assert(tmp);
  862. dst->width = tmp->width;
  863. dst->height = tmp->height;
  864. }
  865. const zbar_format_def_t *tmpfmt = _zbar_format_lookup(tmp->format);
  866. assert(tmpfmt);
  867. /* convert to intermediate format */
  868. _zbar_convert_jpeg_to_y(tmp, tmpfmt, src, srcfmt);
  869. /* now convert to dst */
  870. dst->width = tmp->width;
  871. dst->height = tmp->height;
  872. conversion_handler_t *func =
  873. conversions[tmpfmt->group][dstfmt->group].func;
  874. func(dst, dstfmt, tmp, tmpfmt);
  875. if(!src->src)
  876. zbar_image_destroy(tmp);
  877. }
  878. #endif
  879. zbar_image_t *zbar_image_convert_resize (const zbar_image_t *src,
  880. unsigned long fmt,
  881. unsigned width,
  882. unsigned height)
  883. {
  884. zbar_image_t *dst = zbar_image_create();
  885. dst->format = fmt;
  886. dst->width = width;
  887. dst->height = height;
  888. if(src->format == fmt &&
  889. src->width == width &&
  890. src->height == height) {
  891. convert_copy(dst, NULL, src, NULL);
  892. return(dst);
  893. }
  894. const zbar_format_def_t *srcfmt = _zbar_format_lookup(src->format);
  895. const zbar_format_def_t *dstfmt = _zbar_format_lookup(dst->format);
  896. if(!srcfmt || !dstfmt)
  897. /* FIXME free dst */
  898. return(NULL);
  899. if(srcfmt->group == dstfmt->group &&
  900. srcfmt->p.cmp == dstfmt->p.cmp &&
  901. src->width == width &&
  902. src->height == height) {
  903. convert_copy(dst, NULL, src, NULL);
  904. return(dst);
  905. }
  906. conversion_handler_t *func =
  907. conversions[srcfmt->group][dstfmt->group].func;
  908. dst->cleanup = zbar_image_free_data;
  909. func(dst, dstfmt, src, srcfmt);
  910. if(!dst->data) {
  911. /* conversion failed */
  912. zbar_image_destroy(dst);
  913. return(NULL);
  914. }
  915. return(dst);
  916. }
  917. zbar_image_t *zbar_image_convert (const zbar_image_t *src,
  918. unsigned long fmt)
  919. {
  920. return(zbar_image_convert_resize(src, fmt, src->width, src->height));
  921. }
  922. static inline int has_format (uint32_t fmt,
  923. const uint32_t *fmts)
  924. {
  925. for(; *fmts; fmts++)
  926. if(*fmts == fmt)
  927. return(1);
  928. return(0);
  929. }
  930. /* select least cost conversion from src format to available dsts */
  931. int _zbar_best_format (uint32_t src,
  932. uint32_t *dst,
  933. const uint32_t *dsts)
  934. {
  935. if(dst)
  936. *dst = 0;
  937. if(!dsts)
  938. return(-1);
  939. if(has_format(src, dsts)) {
  940. zprintf(8, "shared format: %4.4s\n", (char*)&src);
  941. if(dst)
  942. *dst = src;
  943. return(0);
  944. }
  945. const zbar_format_def_t *srcfmt = _zbar_format_lookup(src);
  946. if(!srcfmt)
  947. return(-1);
  948. zprintf(8, "from %.4s(%08" PRIx32 ") to", (char*)&src, src);
  949. unsigned min_cost = -1;
  950. for(; *dsts; dsts++) {
  951. const zbar_format_def_t *dstfmt = _zbar_format_lookup(*dsts);
  952. if(!dstfmt)
  953. continue;
  954. int cost;
  955. if(srcfmt->group == dstfmt->group &&
  956. srcfmt->p.cmp == dstfmt->p.cmp)
  957. cost = 0;
  958. else
  959. cost = conversions[srcfmt->group][dstfmt->group].cost;
  960. #if 0
  961. if(_zbar_verbosity >= 8)
  962. fprintf(stderr, " %.4s(%08" PRIx32 ")=%d",
  963. (char*)dsts, *dsts, cost);
  964. #endif
  965. if(cost >= 0 && min_cost > cost) {
  966. min_cost = cost;
  967. if(dst)
  968. *dst = *dsts;
  969. }
  970. }
  971. #if 0
  972. if(_zbar_verbosity >= 8)
  973. fprintf(stderr, "\n");
  974. #endif
  975. return(min_cost);
  976. }
  977. int zbar_negotiate_format (zbar_video_t *vdo,
  978. zbar_window_t *win)
  979. {
  980. if(!vdo && !win)
  981. return(0);
  982. if(win)
  983. (void)window_lock(win);
  984. errinfo_t *errdst = (vdo) ? &vdo->err : &win->err;
  985. if(verify_format_sort()) {
  986. if(win)
  987. (void)window_unlock(win);
  988. return(err_capture(errdst, SEV_FATAL, ZBAR_ERR_INTERNAL, __func__,
  989. "image format list is not sorted!?"));
  990. }
  991. if((vdo && !vdo->formats) || (win && !win->formats)) {
  992. if(win)
  993. (void)window_unlock(win);
  994. return(err_capture(errdst, SEV_ERROR, ZBAR_ERR_UNSUPPORTED, __func__,
  995. "no input or output formats available"));
  996. }
  997. static const uint32_t y800[2] = { fourcc('Y','8','0','0'), 0 };
  998. const uint32_t *srcs = (vdo) ? vdo->formats : y800;
  999. const uint32_t *dsts = (win) ? win->formats : y800;
  1000. unsigned min_cost = -1;
  1001. uint32_t min_fmt = 0;
  1002. const uint32_t *fmt;
  1003. for(fmt = _zbar_formats; *fmt; fmt++) {
  1004. /* only consider formats supported by video device */
  1005. if(!has_format(*fmt, srcs))
  1006. continue;
  1007. uint32_t win_fmt = 0;
  1008. int cost = _zbar_best_format(*fmt, &win_fmt, dsts);
  1009. if(cost < 0) {
  1010. zprintf(4, "%.4s(%08" PRIx32 ") -> ? (unsupported)\n",
  1011. (char*)fmt, *fmt);
  1012. continue;
  1013. }
  1014. zprintf(4, "%.4s(%08" PRIx32 ") -> %.4s(%08" PRIx32 ") (%d)\n",
  1015. (char*)fmt, *fmt, (char*)&win_fmt, win_fmt, cost);
  1016. if(min_cost > cost) {
  1017. min_cost = cost;
  1018. min_fmt = *fmt;
  1019. if(!cost)
  1020. break;
  1021. }
  1022. }
  1023. if(win)
  1024. (void)window_unlock(win);
  1025. if(!min_fmt)
  1026. return(err_capture(errdst, SEV_ERROR, ZBAR_ERR_UNSUPPORTED, __func__,
  1027. "no supported image formats available"));
  1028. if(!vdo)
  1029. return(0);
  1030. zprintf(2, "setting best format %.4s(%08" PRIx32 ") (%d)\n",
  1031. (char*)&min_fmt, min_fmt, min_cost);
  1032. return(zbar_video_init(vdo, min_fmt));
  1033. }