1 /*********************************************************************
2 *********************************************************************/
3 /*********************************************************************
4 * added and modified some function for support and help for Android
5 * Copyright (C) 2014 saki@serenegiant All rights reserved.
7 * added some helper functions for supporting rgb565 and rgbx8888
9 * modified for optimization with gcc
10 * modified macros that convert pixel format to reduce cpu cycles
11 * added boundary check of pointer in the converting function to avoid crash
12 *********************************************************************/
14 /*********************************************************************
15 * Software License Agreement (BSD License)
17 * Copyright (C) 2010-2012 Ken Tossell
18 * All rights reserved.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
24 * * Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * * Redistributions in binary form must reproduce the above
27 * copyright notice, this list of conditions and the following
28 * disclaimer in the documentation and/or other materials provided
29 * with the distribution.
30 * * Neither the name of the author nor other contributors may be
31 * used to endorse or promote products derived from this software
32 * without specific prior written permission.
34 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
35 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
36 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
37 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
38 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
40 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
41 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
42 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
44 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45 * POSSIBILITY OF SUCH DAMAGE.
46 *********************************************************************/
48 * @defgroup frame Frame processing
49 * @brief Tools for managing frame buffers and converting between image formats
51 #include "libuvc/libuvc.h"
52 #include "libuvc/libuvc_internal.h"
56 uvc_error_t uvc_ensure_frame_size(uvc_frame_t *frame, size_t need_bytes) {
57 if LIKELY(frame->library_owns_data) {
58 if UNLIKELY(!frame->data || frame->data_bytes != need_bytes) {
59 frame->actual_bytes = frame->data_bytes = need_bytes; // XXX
60 frame->data = realloc(frame->data, frame->data_bytes);
62 if (UNLIKELY(!frame->data || !need_bytes))
63 return UVC_ERROR_NO_MEM;
66 if (UNLIKELY(!frame->data || frame->data_bytes < need_bytes))
67 return UVC_ERROR_NO_MEM;
72 /** @brief Allocate a frame structure
75 * @param data_bytes Number of bytes to allocate, or zero
76 * @return New frame, or NULL on error
78 uvc_frame_t *uvc_allocate_frame(size_t data_bytes) {
79 uvc_frame_t *frame = malloc(sizeof(*frame)); // FIXME using buffer pool is better performance(5-30%) than directory use malloc everytime.
85 // XXX in many case, it is not neccesary to clear because all fields are set before use
86 // therefore we remove this to improve performace, but be care not to forget to set fields before use
87 memset(frame, 0, sizeof(*frame)); // bzero(frame, sizeof(*frame)); // bzero is deprecated
89 // frame->library_owns_data = 1; // XXX moved to lower
91 if (LIKELY(data_bytes > 0)) {
92 frame->library_owns_data = 1;
93 frame->actual_bytes = frame->data_bytes = data_bytes; // XXX
94 frame->data = malloc(data_bytes);
96 if (UNLIKELY(!frame->data)) {
105 /** @brief Free a frame structure
108 * @param frame Frame to destroy
110 void uvc_free_frame(uvc_frame_t *frame) {
111 if ((frame->data_bytes > 0) && frame->library_owns_data)
117 static inline unsigned char sat(int i) {
118 return (unsigned char) (i >= 255 ? 255 : (i < 0 ? 0 : i));
121 /** @brief Duplicate a frame, preserving color format
124 * @param in Original frame
125 * @param out Duplicate frame
127 uvc_error_t uvc_duplicate_frame(uvc_frame_t *in, uvc_frame_t *out) {
128 if (UNLIKELY(uvc_ensure_frame_size(out, in->data_bytes) < 0))
129 return UVC_ERROR_NO_MEM;
131 out->width = in->width;
132 out->height = in->height;
133 out->frame_format = in->frame_format;
134 if (out->library_owns_data)
135 out->step = in->step;
136 out->sequence = in->sequence;
137 out->capture_time = in->capture_time;
138 out->source = in->source;
139 out->actual_bytes = in->actual_bytes; // XXX
141 #if USE_STRIDE // XXX
142 if (in->step && out->step) {
143 const int istep = in->step;
144 const int ostep = out->step;
145 const int hh = in->height < out->height ? in->height : out->height;
146 const int rowbytes = istep < ostep ? istep : ostep;
147 register void *ip = in->data;
148 register void *op = out->data;
150 for (h = 0; h < hh; h += 4) {
151 memcpy(op, ip, rowbytes);
152 ip += istep; op += ostep;
153 memcpy(op, ip, rowbytes);
154 ip += istep; op += ostep;
155 memcpy(op, ip, rowbytes);
156 ip += istep; op += ostep;
157 memcpy(op, ip, rowbytes);
158 ip += istep; op += ostep;
161 // compressed format? XXX if only one of the frame in / out has step, this may lead to crash...
162 memcpy(out->data, in->data, in->actual_bytes);
165 memcpy(out->data, in->data, in->actual_bytes); // XXX
170 #define PIXEL_RGB565 2
177 #define PIXEL2_RGB565 PIXEL_RGB565 * 2
178 #define PIXEL2_UYVY PIXEL_UYVY * 2
179 #define PIXEL2_YUYV PIXEL_YUYV * 2
180 #define PIXEL2_RGB PIXEL_RGB * 2
181 #define PIXEL2_BGR PIXEL_BGR * 2
182 #define PIXEL2_RGBX PIXEL_RGBX * 2
184 #define PIXEL4_RGB565 PIXEL_RGB565 * 4
185 #define PIXEL4_UYVY PIXEL_UYVY * 4
186 #define PIXEL4_YUYV PIXEL_YUYV * 4
187 #define PIXEL4_RGB PIXEL_RGB * 4
188 #define PIXEL4_BGR PIXEL_BGR * 4
189 #define PIXEL4_RGBX PIXEL_RGBX * 4
191 #define PIXEL8_RGB565 PIXEL_RGB565 * 8
192 #define PIXEL8_UYVY PIXEL_UYVY * 8
193 #define PIXEL8_YUYV PIXEL_YUYV * 8
194 #define PIXEL8_RGB PIXEL_RGB * 8
195 #define PIXEL8_BGR PIXEL_BGR * 8
196 #define PIXEL8_RGBX PIXEL_RGBX * 8
198 #define PIXEL16_RGB565 PIXEL_RGB565 * 16
199 #define PIXEL16_UYVY PIXEL_UYVY * 16
200 #define PIXEL16_YUYV PIXEL_YUYV * 16
201 #define PIXEL16_RGB PIXEL_RGB * 16
202 #define PIXEL16_BGR PIXEL_BGR * 16
203 #define PIXEL16_RGBX PIXEL_RGBX * 16
205 #define RGB2RGBX_2(prgb, prgbx, ax, bx) { \
206 (prgbx)[bx+0] = (prgb)[ax+0]; \
207 (prgbx)[bx+1] = (prgb)[ax+1]; \
208 (prgbx)[bx+2] = (prgb)[ax+2]; \
209 (prgbx)[bx+3] = 0xff; \
210 (prgbx)[bx+4] = (prgb)[ax+3]; \
211 (prgbx)[bx+5] = (prgb)[ax+4]; \
212 (prgbx)[bx+6] = (prgb)[ax+5]; \
213 (prgbx)[bx+7] = 0xff; \
215 #define RGB2RGBX_16(prgb, prgbx, ax, bx) \
216 RGB2RGBX_8(prgb, prgbx, ax, bx) \
217 RGB2RGBX_8(prgb, prgbx, ax + PIXEL8_RGB, bx +PIXEL8_RGBX);
218 #define RGB2RGBX_8(prgb, prgbx, ax, bx) \
219 RGB2RGBX_4(prgb, prgbx, ax, bx) \
220 RGB2RGBX_4(prgb, prgbx, ax + PIXEL4_RGB, bx + PIXEL4_RGBX);
221 #define RGB2RGBX_4(prgb, prgbx, ax, bx) \
222 RGB2RGBX_2(prgb, prgbx, ax, bx) \
223 RGB2RGBX_2(prgb, prgbx, ax + PIXEL2_RGB, bx + PIXEL2_RGBX);
225 /** @brief Convert a frame from RGB888 to RGBX8888
227 * @param ini RGB888 frame
228 * @param out RGBX8888 frame
230 uvc_error_t uvc_rgb2rgbx(uvc_frame_t *in, uvc_frame_t *out) {
231 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_RGB))
232 return UVC_ERROR_INVALID_PARAM;
234 if (UNLIKELY(uvc_ensure_frame_size(out, in->width * in->height * PIXEL_RGBX) < 0))
235 return UVC_ERROR_NO_MEM;
237 out->width = in->width;
238 out->height = in->height;
239 out->frame_format = UVC_FRAME_FORMAT_RGBX;
240 if (out->library_owns_data)
241 out->step = in->width * PIXEL_RGBX;
242 out->sequence = in->sequence;
243 out->capture_time = in->capture_time;
244 out->source = in->source;
246 uint8_t *prgb = in->data;
247 const uint8_t *prgb_end = prgb + in->data_bytes - PIXEL8_RGB;
248 uint8_t *prgbx = out->data;
249 const uint8_t *prgbx_end = prgbx + out->data_bytes - PIXEL8_RGBX;
251 // RGB888 to RGBX8888
253 if (in->step && out->step && (in->step != out->step)) {
254 const int hh = in->height < out->height ? in->height : out->height;
255 const int ww = in->width < out->width ? in->width : out->width;
257 for (h = 0; h < hh; h++) {
259 prgb = in->data + in->step * h;
260 prgbx = out->data + out->step * h;
261 for (; (prgbx <= prgbx_end) && (prgb <= prgb_end) && (w < ww) ;) {
262 RGB2RGBX_8(prgb, prgbx, 0, 0);
265 prgbx += PIXEL8_RGBX;
270 // compressed format? XXX if only one of the frame in / out has step, this may lead to crash...
271 for (; (prgbx <= prgbx_end) && (prgb <= prgb_end) ;) {
272 RGB2RGBX_8(prgb, prgbx, 0, 0);
275 prgbx += PIXEL8_RGBX;
279 for (; (prgbx <= prgbx_end) && (prgb <= prgb_end) ;) {
280 RGB2RGBX_8(prgb, prgbx, 0, 0);
283 prgbx += PIXEL8_RGBX;
289 // prgb565[0] = ((g << 3) & 0b11100000) | ((b >> 3) & 0b00011111); // low byte
290 // prgb565[1] = ((r & 0b11111000) | ((g >> 5) & 0b00000111)); // high byte
291 #define RGB2RGB565_2(prgb, prgb565, ax, bx) { \
292 (prgb565)[bx+0] = (((prgb)[ax+1] << 3) & 0b11100000) | (((prgb)[ax+2] >> 3) & 0b00011111); \
293 (prgb565)[bx+1] = (((prgb)[ax+0] & 0b11111000) | (((prgb)[ax+1] >> 5) & 0b00000111)); \
294 (prgb565)[bx+2] = (((prgb)[ax+4] << 3) & 0b11100000) | (((prgb)[ax+5] >> 3) & 0b00011111); \
295 (prgb565)[bx+3] = (((prgb)[ax+3] & 0b11111000) | (((prgb)[ax+4] >> 5) & 0b00000111)); \
297 #define RGB2RGB565_16(prgb, prgb565, ax, bx) \
298 RGB2RGB565_8(prgb, prgb565, ax, bx) \
299 RGB2RGB565_8(prgb, prgb565, ax + PIXEL8_RGB, bx + PIXEL8_RGB565);
300 #define RGB2RGB565_8(prgb, prgb565, ax, bx) \
301 RGB2RGB565_4(prgb, prgb565, ax, bx) \
302 RGB2RGB565_4(prgb, prgb565, ax + PIXEL4_RGB, bx + PIXEL4_RGB565);
303 #define RGB2RGB565_4(prgb, prgb565, ax, bx) \
304 RGB2RGB565_2(prgb, prgb565, ax, bx) \
305 RGB2RGB565_2(prgb, prgb565, ax + PIXEL2_RGB, bx + PIXEL2_RGB565);
307 /** @brief Convert a frame from RGB888 to RGB565
309 * @param ini RGB888 frame
310 * @param out RGB565 frame
312 uvc_error_t uvc_rgb2rgb565(uvc_frame_t *in, uvc_frame_t *out) {
313 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_RGB))
314 return UVC_ERROR_INVALID_PARAM;
316 if (UNLIKELY(uvc_ensure_frame_size(out, in->width * in->height * PIXEL_RGB565) < 0))
317 return UVC_ERROR_NO_MEM;
319 out->width = in->width;
320 out->height = in->height;
321 out->frame_format = UVC_FRAME_FORMAT_RGB565;
322 if (out->library_owns_data)
323 out->step = in->width * PIXEL_RGB565;
324 out->sequence = in->sequence;
325 out->capture_time = in->capture_time;
326 out->source = in->source;
328 uint8_t *prgb = in->data;
329 const uint8_t *prgb_end = prgb + in->data_bytes - PIXEL8_RGB;
330 uint8_t *prgb565 = out->data;
331 const uint8_t *prgb565_end = prgb565 + out->data_bytes - PIXEL8_RGB565;
335 if (in->step && out->step && (in->step != out->step)) {
336 const int hh = in->height < out->height ? in->height : out->height;
337 const int ww = in->width < out->width ? in->width : out->width;
339 for (h = 0; h < hh; h++) {
341 prgb = in->data + in->step * h;
342 prgb565 = out->data + out->step * h;
343 for (; (prgb565 <= prgb565_end) && (prgb <= prgb_end) && (w < ww) ;) {
344 RGB2RGB565_8(prgb, prgb565, 0, 0);
347 prgb565 += PIXEL8_RGB565;
352 // compressed format? XXX if only one of the frame in / out has step, this may lead to crash...
353 for (; (prgb565 <= prgb565_end) && (prgb <= prgb_end) ;) {
354 RGB2RGB565_8(prgb, prgb565, 0, 0);
357 prgb565 += PIXEL8_RGB565;
361 for (; (prgb565 <= prgb565_end) && (prgb <= prgb_end) ;) {
362 RGB2RGB565_8(prgb, prgb565, 0, 0);
365 prgb565 += PIXEL8_RGB565;
371 #define YUYV2RGB_2(pyuv, prgb) { \
372 float r = 1.402f * ((pyuv)[3]-128); \
373 float g = -0.34414f * ((pyuv)[1]-128) - 0.71414f * ((pyuv)[3]-128); \
374 float b = 1.772f * ((pyuv)[1]-128); \
375 (prgb)[0] = sat(pyuv[0] + r); \
376 (prgb)[1] = sat(pyuv[0] + g); \
377 (prgb)[2] = sat(pyuv[0] + b); \
378 (prgb)[3] = sat(pyuv[2] + r); \
379 (prgb)[4] = sat(pyuv[2] + g); \
380 (prgb)[5] = sat(pyuv[2] + b); \
384 #define IYUYV2RGB_2(pyuv, prgb, ax, bx) { \
385 const int d1 = (pyuv)[ax+1]; \
386 const int d3 = (pyuv)[ax+3]; \
387 const int r = (22987 * (d3/*(pyuv)[ax+3]*/ - 128)) >> 14; \
388 const int g = (-5636 * (d1/*(pyuv)[ax+1]*/ - 128) - 11698 * (d3/*(pyuv)[ax+3]*/ - 128)) >> 14; \
389 const int b = (29049 * (d1/*(pyuv)[ax+1]*/ - 128)) >> 14; \
390 const int y0 = (pyuv)[ax+0]; \
391 (prgb)[bx+0] = sat(y0 + r); \
392 (prgb)[bx+1] = sat(y0 + g); \
393 (prgb)[bx+2] = sat(y0 + b); \
394 const int y2 = (pyuv)[ax+2]; \
395 (prgb)[bx+3] = sat(y2 + r); \
396 (prgb)[bx+4] = sat(y2 + g); \
397 (prgb)[bx+5] = sat(y2 + b); \
399 #define IYUYV2RGB_16(pyuv, prgb, ax, bx) \
400 IYUYV2RGB_8(pyuv, prgb, ax, bx) \
401 IYUYV2RGB_8(pyuv, prgb, ax + PIXEL8_YUYV, bx + PIXEL8_RGB)
402 #define IYUYV2RGB_8(pyuv, prgb, ax, bx) \
403 IYUYV2RGB_4(pyuv, prgb, ax, bx) \
404 IYUYV2RGB_4(pyuv, prgb, ax + PIXEL4_YUYV, bx + PIXEL4_RGB)
405 #define IYUYV2RGB_4(pyuv, prgb, ax, bx) \
406 IYUYV2RGB_2(pyuv, prgb, ax, bx) \
407 IYUYV2RGB_2(pyuv, prgb, ax + PIXEL2_YUYV, bx + PIXEL2_RGB)
409 /** @brief Convert a frame from YUYV to RGB888
412 * @param in YUYV frame
413 * @param out RGB888 frame
415 uvc_error_t uvc_yuyv2rgb(uvc_frame_t *in, uvc_frame_t *out) {
416 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_YUYV))
417 return UVC_ERROR_INVALID_PARAM;
419 if (UNLIKELY(uvc_ensure_frame_size(out, in->width * in->height * PIXEL_RGB) < 0))
420 return UVC_ERROR_NO_MEM;
422 out->width = in->width;
423 out->height = in->height;
424 out->frame_format = UVC_FRAME_FORMAT_RGB;
425 if (out->library_owns_data)
426 out->step = in->width * PIXEL_RGB;
427 out->sequence = in->sequence;
428 out->capture_time = in->capture_time;
429 out->source = in->source;
431 uint8_t *pyuv = in->data;
432 const uint8_t *pyuv_end = pyuv + in->data_bytes - PIXEL8_YUYV;
433 uint8_t *prgb = out->data;
434 const uint8_t *prgb_end = prgb + out->data_bytes - PIXEL8_RGB;
437 if (in->step && out->step && (in->step != out->step)) {
438 const int hh = in->height < out->height ? in->height : out->height;
439 const int ww = in->width < out->width ? in->width : out->width;
441 for (h = 0; h < hh; h++) {
443 pyuv = in->data + in->step * h;
444 prgb = out->data + out->step * h;
445 for (; (prgb <= prgb_end) && (pyuv <= pyuv_end) && (w < ww) ;) {
446 IYUYV2RGB_8(pyuv, prgb, 0, 0);
454 // compressed format? XXX if only one of the frame in / out has step, this may lead to crash...
455 for (; (prgb <= prgb_end) && (pyuv <= pyuv_end) ;) {
456 IYUYV2RGB_8(pyuv, prgb, 0, 0);
464 for (; (prgb <= prgb_end) && (pyuv <= pyuv_end) ;) {
465 IYUYV2RGB_8(pyuv, prgb, 0, 0);
474 /** @brief Convert a frame from YUYV to RGB565
476 * @param ini YUYV frame
477 * @param out RGB565 frame
479 uvc_error_t uvc_yuyv2rgb565(uvc_frame_t *in, uvc_frame_t *out) {
480 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_YUYV))
481 return UVC_ERROR_INVALID_PARAM;
483 if (UNLIKELY(uvc_ensure_frame_size(out, in->width * in->height * PIXEL_RGB565) < 0))
484 return UVC_ERROR_NO_MEM;
486 out->width = in->width;
487 out->height = in->height;
488 out->frame_format = UVC_FRAME_FORMAT_RGB565;
489 if (out->library_owns_data)
490 out->step = in->width * PIXEL_RGB565;
491 out->sequence = in->sequence;
492 out->capture_time = in->capture_time;
493 out->source = in->source;
495 uint8_t *pyuv = in->data;
496 const uint8_t *pyuv_end = pyuv + in->data_bytes - PIXEL8_YUYV;
497 uint8_t *prgb565 = out->data;
498 const uint8_t *prgb565_end = prgb565 + out->data_bytes - PIXEL8_RGB565;
500 uint8_t tmp[PIXEL8_RGB]; // for temporary rgb888 data(8pixel)
503 if (in->step && out->step && (in->step != out->step)) {
504 const int hh = in->height < out->height ? in->height : out->height;
505 const int ww = in->width < out->width ? in->width : out->width;
507 for (h = 0; h < hh; h++) {
509 pyuv = in->data + in->step * h;
510 prgb565 = out->data + out->step * h;
511 for (; (prgb565 <= prgb565_end) && (pyuv <= pyuv_end) && (w < ww) ;) {
512 IYUYV2RGB_8(pyuv, tmp, 0, 0);
513 RGB2RGB565_8(tmp, prgb565, 0, 0);
515 prgb565 += PIXEL8_YUYV;
516 pyuv += PIXEL8_RGB565;
521 // compressed format? XXX if only one of the frame in / out has step, this may lead to crash...
522 for (; (prgb565 <= prgb565_end) && (pyuv <= pyuv_end) ;) {
523 IYUYV2RGB_8(pyuv, tmp, 0, 0);
524 RGB2RGB565_8(tmp, prgb565, 0, 0);
526 prgb565 += PIXEL8_YUYV;
527 pyuv += PIXEL8_RGB565;
532 for (; (prgb565 <= prgb565_end) && (pyuv <= pyuv_end) ;) {
533 IYUYV2RGB_8(pyuv, tmp, 0, 0);
534 RGB2RGB565_8(tmp, prgb565, 0, 0);
536 prgb565 += PIXEL8_YUYV;
537 pyuv += PIXEL8_RGB565;
543 #define IYUYV2RGBX_2(pyuv, prgbx, ax, bx) { \
544 const int d1 = (pyuv)[ax+1]; \
545 const int d3 = (pyuv)[ax+3]; \
546 const int r = (22987 * (d3/*(pyuv)[ax+3]*/ - 128)) >> 14; \
547 const int g = (-5636 * (d1/*(pyuv)[ax+1]*/ - 128) - 11698 * (d3/*(pyuv)[ax+3]*/ - 128)) >> 14; \
548 const int b = (29049 * (d1/*(pyuv)[ax+1]*/ - 128)) >> 14; \
549 const int y0 = (pyuv)[ax+0]; \
550 (prgbx)[bx+0] = sat(y0 + r); \
551 (prgbx)[bx+1] = sat(y0 + g); \
552 (prgbx)[bx+2] = sat(y0 + b); \
553 (prgbx)[bx+3] = 0xff; \
554 const int y2 = (pyuv)[ax+2]; \
555 (prgbx)[bx+4] = sat(y2 + r); \
556 (prgbx)[bx+5] = sat(y2 + g); \
557 (prgbx)[bx+6] = sat(y2 + b); \
558 (prgbx)[bx+7] = 0xff; \
560 #define IYUYV2RGBX_16(pyuv, prgbx, ax, bx) \
561 IYUYV2RGBX_8(pyuv, prgbx, ax, bx) \
562 IYUYV2RGBX_8(pyuv, prgbx, ax + PIXEL8_YUYV, bx + PIXEL8_RGBX);
563 #define IYUYV2RGBX_8(pyuv, prgbx, ax, bx) \
564 IYUYV2RGBX_4(pyuv, prgbx, ax, bx) \
565 IYUYV2RGBX_4(pyuv, prgbx, ax + PIXEL4_YUYV, bx + PIXEL4_RGBX);
566 #define IYUYV2RGBX_4(pyuv, prgbx, ax, bx) \
567 IYUYV2RGBX_2(pyuv, prgbx, ax, bx) \
568 IYUYV2RGBX_2(pyuv, prgbx, ax + PIXEL2_YUYV, bx + PIXEL2_RGBX);
570 /** @brief Convert a frame from YUYV to RGBX8888
572 * @param ini YUYV frame
573 * @param out RGBX8888 frame
575 uvc_error_t uvc_yuyv2rgbx(uvc_frame_t *in, uvc_frame_t *out) {
576 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_YUYV))
577 return UVC_ERROR_INVALID_PARAM;
579 if (UNLIKELY(uvc_ensure_frame_size(out, in->width * in->height * PIXEL_RGBX) < 0))
580 return UVC_ERROR_NO_MEM;
582 out->width = in->width;
583 out->height = in->height;
584 out->frame_format = UVC_FRAME_FORMAT_RGBX;
585 if (out->library_owns_data)
586 out->step = in->width * PIXEL_RGBX;
587 out->sequence = in->sequence;
588 out->capture_time = in->capture_time;
589 out->source = in->source;
591 uint8_t *pyuv = in->data;
592 const uint8_t *pyuv_end = pyuv + in->data_bytes - PIXEL8_YUYV;
593 uint8_t *prgbx = out->data;
594 const uint8_t *prgbx_end = prgbx + out->data_bytes - PIXEL8_RGBX;
598 if (in->step && out->step && (in->step != out->step)) {
599 const int hh = in->height < out->height ? in->height : out->height;
600 const int ww = in->width < out->width ? in->width : out->width;
602 for (h = 0; h < hh; h++) {
604 pyuv = in->data + in->step * h;
605 prgbx = out->data + out->step * h;
606 for (; (prgbx <= prgbx_end) && (pyuv <= pyuv_end) && (w < ww) ;) {
607 IYUYV2RGBX_8(pyuv, prgbx, 0, 0);
609 prgbx += PIXEL8_RGBX;
615 // compressed format? XXX if only one of the frame in / out has step, this may lead to crash...
616 for (; (prgbx <= prgbx_end) && (pyuv <= pyuv_end) ;) {
617 IYUYV2RGBX_8(pyuv, prgbx, 0, 0);
619 prgbx += PIXEL8_RGBX;
624 for (; (prgbx <= prgbx_end) && (pyuv <= pyuv_end) ;) {
625 IYUYV2RGBX_8(pyuv, prgbx, 0, 0);
627 prgbx += PIXEL8_RGBX;
634 #define IYUYV2BGR_2(pyuv, pbgr, ax, bx) { \
635 const int d1 = (pyuv)[1]; \
636 const int d3 = (pyuv)[3]; \
637 const int r = (22987 * (d3/*(pyuv)[3]*/ - 128)) >> 14; \
638 const int g = (-5636 * (d1/*(pyuv)[1]*/ - 128) - 11698 * (d3/*(pyuv)[3]*/ - 128)) >> 14; \
639 const int b = (29049 * (d1/*(pyuv)[1]*/ - 128)) >> 14; \
640 const int y0 = (pyuv)[ax+0]; \
641 (pbgr)[bx+0] = sat(y0 + b); \
642 (pbgr)[bx+1] = sat(y0 + g); \
643 (pbgr)[bx+2] = sat(y0 + r); \
644 const int y2 = (pyuv)[ax+2]; \
645 (pbgr)[bx+3] = sat(y2 + b); \
646 (pbgr)[bx+4] = sat(y2 + g); \
647 (pbgr)[bx+5] = sat(y2 + r); \
649 #define IYUYV2BGR_16(pyuv, pbgr, ax, bx) \
650 IYUYV2BGR_8(pyuv, pbgr, ax, bx) \
651 IYUYV2BGR_8(pyuv, pbgr, ax + PIXEL8_YUYV, bx + PIXEL8_BGR)
652 #define IYUYV2BGR_8(pyuv, pbgr, ax, bx) \
653 IYUYV2BGR_4(pyuv, pbgr, ax, bx) \
654 IYUYV2BGR_4(pyuv, pbgr, ax + PIXEL4_YUYV, bx + PIXEL4_BGR)
655 #define IYUYV2BGR_4(pyuv, pbgr, ax, bx) \
656 IYUYV2BGR_2(pyuv, pbgr, ax, bx) \
657 IYUYV2BGR_2(pyuv, pbgr, ax + PIXEL2_YUYV, bx + PIXEL2_BGR)
659 /** @brief Convert a frame from YUYV to BGR888
662 * @param in YUYV frame
663 * @param out BGR888 frame
665 uvc_error_t uvc_yuyv2bgr(uvc_frame_t *in, uvc_frame_t *out) {
666 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_YUYV))
667 return UVC_ERROR_INVALID_PARAM;
669 if (UNLIKELY(uvc_ensure_frame_size(out, in->width * in->height * PIXEL_BGR) < 0))
670 return UVC_ERROR_NO_MEM;
672 out->width = in->width;
673 out->height = in->height;
674 out->frame_format = UVC_FRAME_FORMAT_BGR;
675 if (out->library_owns_data)
676 out->step = in->width * PIXEL_BGR;
677 out->sequence = in->sequence;
678 out->capture_time = in->capture_time;
679 out->source = in->source;
681 uint8_t *pyuv = in->data;
682 uint8_t *pyuv_end = pyuv + in->data_bytes - PIXEL8_YUYV;
683 uint8_t *pbgr = out->data;
684 uint8_t *pbgr_end = pbgr + out->data_bytes - PIXEL8_BGR;
688 if (in->step && out->step && (in->step != out->step)) {
689 const int hh = in->height < out->height ? in->height : out->height;
690 const int ww = in->width < out->width ? in->width : out->width;
692 for (h = 0; h < hh; h++) {
694 pyuv = in->data + in->step * h;
695 pbgr = out->data + out->step * h;
696 for (; (pbgr <= pbgr_end) && (pyuv <= pyuv_end) && (w < ww) ;) {
697 IYUYV2BGR_8(pyuv, pbgr, 0, 0);
705 // compressed format? XXX if only one of the frame in / out has step, this may lead to crash...
706 for (; (pbgr <= pbgr_end) && (pyuv <= pyuv_end) ;) {
707 IYUYV2BGR_8(pyuv, pbgr, 0, 0);
714 for (; (pbgr <= pbgr_end) && (pyuv <= pyuv_end) ;) {
715 IYUYV2BGR_8(pyuv, pbgr, 0, 0);
724 #define IUYVY2RGB_2(pyuv, prgb, ax, bx) { \
725 const int d0 = (pyuv)[ax+0]; \
726 const int d2 = (pyuv)[ax+2]; \
727 const int r = (22987 * (d2/*(pyuv)[ax+2]*/ - 128)) >> 14; \
728 const int g = (-5636 * (d0/*(pyuv)[ax+0]*/ - 128) - 11698 * (d2/*(pyuv)[ax+2]*/ - 128)) >> 14; \
729 const int b = (29049 * (d0/*(pyuv)[ax+0]*/ - 128)) >> 14; \
730 const int y1 = (pyuv)[ax+1]; \
731 (prgb)[bx+0] = sat(y1 + r); \
732 (prgb)[bx+1] = sat(y1 + g); \
733 (prgb)[bx+2] = sat(y1 + b); \
734 const int y3 = (pyuv)[ax+3]; \
735 (prgb)[bx+3] = sat(y3 + r); \
736 (prgb)[bx+4] = sat(y3 + g); \
737 (prgb)[bx+5] = sat(y3 + b); \
739 #define IUYVY2RGB_16(pyuv, prgb, ax, bx) \
740 IUYVY2RGB_8(pyuv, prgb, ax, bx) \
741 IUYVY2RGB_8(pyuv, prgb, ax + 16, bx + 24)
742 #define IUYVY2RGB_8(pyuv, prgb, ax, bx) \
743 IUYVY2RGB_4(pyuv, prgb, ax, bx) \
744 IUYVY2RGB_4(pyuv, prgb, ax + 8, bx + 12)
745 #define IUYVY2RGB_4(pyuv, prgb, ax, bx) \
746 IUYVY2RGB_2(pyuv, prgb, ax, bx) \
747 IUYVY2RGB_2(pyuv, prgb, ax + 4, bx + 6)
749 /** @brief Convert a frame from UYVY to RGB888
751 * @param ini UYVY frame
752 * @param out RGB888 frame
754 uvc_error_t uvc_uyvy2rgb(uvc_frame_t *in, uvc_frame_t *out) {
755 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_UYVY))
756 return UVC_ERROR_INVALID_PARAM;
758 if (UNLIKELY(uvc_ensure_frame_size(out, in->width * in->height * PIXEL_RGB) < 0))
759 return UVC_ERROR_NO_MEM;
761 out->width = in->width;
762 out->height = in->height;
763 out->frame_format = UVC_FRAME_FORMAT_RGB;
764 if (out->library_owns_data)
765 out->step = in->width * PIXEL_RGB;
766 out->sequence = in->sequence;
767 out->capture_time = in->capture_time;
768 out->source = in->source;
770 uint8_t *pyuv = in->data;
771 const uint8_t *pyuv_end = pyuv + in->data_bytes - PIXEL8_UYVY;
772 uint8_t *prgb = out->data;
773 const uint8_t *prgb_end = prgb + out->data_bytes - PIXEL8_RGB;
777 if (in->step && out->step && (in->step != out->step)) {
778 const int hh = in->height < out->height ? in->height : out->height;
779 const int ww = in->width < out->width ? in->width : out->width;
781 for (h = 0; h < hh; h++) {
783 pyuv = in->data + in->step * h;
784 prgb = out->data + out->step * h;
785 for (; (prgb <= prgb_end) && (pyuv <= pyuv_end) && (w < ww) ;) {
786 IUYVY2RGB_8(pyuv, prgb, 0, 0);
794 // compressed format? XXX if only one of the frame in / out has step, this may lead to crash...
795 for (; (prgb <= prgb_end) && (pyuv <= pyuv_end) ;) {
796 IUYVY2RGB_8(pyuv, prgb, 0, 0);
803 for (; ((prgb <= prgb_end) && (pyuv <= pyuv_end) ;) {
804 IUYVY2RGB_8(pyuv, prgb, 0, 0);
813 /** @brief Convert a frame from UYVY to RGB565
815 * @param ini UYVY frame
816 * @param out RGB565 frame
818 uvc_error_t uvc_uyvy2rgb565(uvc_frame_t *in, uvc_frame_t *out) {
819 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_UYVY))
820 return UVC_ERROR_INVALID_PARAM;
822 if (UNLIKELY(uvc_ensure_frame_size(out, in->width * in->height * PIXEL_RGB565) < 0))
823 return UVC_ERROR_NO_MEM;
825 out->width = in->width;
826 out->height = in->height;
827 out->frame_format = UVC_FRAME_FORMAT_RGB565;
828 if (out->library_owns_data)
829 out->step = in->width * PIXEL_RGB565;
830 out->sequence = in->sequence;
831 out->capture_time = in->capture_time;
832 out->source = in->source;
834 uint8_t *pyuv = in->data;
835 const uint8_t *pyuv_end = pyuv + in->data_bytes - PIXEL8_UYVY;
836 uint8_t *prgb565 = out->data;
837 const uint8_t *prgb565_end = prgb565 + out->data_bytes - PIXEL8_RGB565;
839 uint8_t tmp[PIXEL8_RGB]; // for temporary rgb888 data(8pixel)
843 if (in->step && out->step && (in->step != out->step)) {
844 const int hh = in->height < out->height ? in->height : out->height;
845 const int ww = in->width < out->width ? in->width : out->width;
847 for (h = 0; h < hh; h++) {
849 pyuv = in->data + in->step * h;
850 prgb565 = out->data + out->step * h;
851 for (; (prgb565 <= prgb565_end) && (pyuv <= pyuv_end) && (w < ww) ;) {
852 IUYVY2RGB_8(pyuv, tmp, 0, 0);
853 RGB2RGB565_8(tmp, prgb565, 0, 0);
855 prgb565 += PIXEL8_RGB565;
861 // compressed format? XXX if only one of the frame in / out has step, this may lead to crash...
862 for (; (prgb565 <= prgb565_end) && (pyuv <= pyuv_end) ;) {
863 IUYVY2RGB_8(pyuv, tmp, 0, 0);
864 RGB2RGB565_8(tmp, prgb565, 0, 0);
866 prgb565 += PIXEL8_RGB565;
871 for (; (prgb565 <= prgb565_end) && (pyuv <= pyuv_end) ;) {
872 IUYVY2RGB_8(pyuv, tmp, 0, 0);
873 RGB2RGB565_8(tmp, prgb565, 0, 0);
875 prgb565 += PIXEL8_RGB565;
882 #define IUYVY2RGBX_2(pyuv, prgbx, ax, bx) { \
883 const int d0 = (pyuv)[ax+0]; \
884 const int d2 = (pyuv)[ax+2]; \
885 const int r = (22987 * (d2/*(pyuv)[ax+2]*/ - 128)) >> 14; \
886 const int g = (-5636 * (d0/*(pyuv)[ax+0]*/ - 128) - 11698 * (d2/*(pyuv)[ax+2]*/ - 128)) >> 14; \
887 const int b = (29049 * (d0/*(pyuv)[ax+0]*/ - 128)) >> 14; \
888 const int y1 = (pyuv)[ax+1]; \
889 (prgbx)[bx+0] = sat(y1 + r); \
890 (prgbx)[bx+1] = sat(y1 + g); \
891 (prgbx)[bx+2] = sat(y1 + b); \
892 (prgbx)[bx+3] = 0xff; \
893 const int y3 = (pyuv)[ax+3]; \
894 (prgbx)[bx+4] = sat(y3 + r); \
895 (prgbx)[bx+5] = sat(y3 + g); \
896 (prgbx)[bx+6] = sat(y3 + b); \
897 (prgbx)[bx+7] = 0xff; \
899 #define IUYVY2RGBX_16(pyuv, prgbx, ax, bx) \
900 IUYVY2RGBX_8(pyuv, prgbx, ax, bx) \
901 IUYVY2RGBX_8(pyuv, prgbx, ax + PIXEL8_UYVY, bx + PIXEL8_RGBX)
902 #define IUYVY2RGBX_8(pyuv, prgbx, ax, bx) \
903 IUYVY2RGBX_4(pyuv, prgbx, ax, bx) \
904 IUYVY2RGBX_4(pyuv, prgbx, ax + PIXEL4_UYVY, bx + PIXEL4_RGBX)
905 #define IUYVY2RGBX_4(pyuv, prgbx, ax, bx) \
906 IUYVY2RGBX_2(pyuv, prgbx, ax, bx) \
907 IUYVY2RGBX_2(pyuv, prgbx, ax + PIXEL2_UYVY, bx + PIXEL2_RGBX)
909 /** @brief Convert a frame from UYVY to RGBX8888
911 * @param ini UYVY frame
912 * @param out RGBX8888 frame
914 uvc_error_t uvc_uyvy2rgbx(uvc_frame_t *in, uvc_frame_t *out) {
915 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_UYVY))
916 return UVC_ERROR_INVALID_PARAM;
918 if (UNLIKELY(uvc_ensure_frame_size(out, in->width * in->height * PIXEL_RGBX) < 0))
919 return UVC_ERROR_NO_MEM;
921 out->width = in->width;
922 out->height = in->height;
923 out->frame_format = UVC_FRAME_FORMAT_RGBX;
924 if (out->library_owns_data)
925 out->step = in->width * PIXEL_RGBX;
926 out->sequence = in->sequence;
927 out->capture_time = in->capture_time;
928 out->source = in->source;
930 uint8_t *pyuv = in->data;
931 const uint8_t *pyuv_end = pyuv + in->data_bytes - PIXEL8_UYVY;
932 uint8_t *prgbx = out->data;
933 const uint8_t *prgbx_end = prgbx + out->data_bytes - PIXEL8_RGBX;
937 if (in->step && out->step && (in->step != out->step)) {
938 const int hh = in->height < out->height ? in->height : out->height;
939 const int ww = in->width < out->width ? in->width : out->width;
941 for (h = 0; h < hh; h++) {
943 pyuv = in->data + in->step * h;
944 prgbx = out->data + out->step * h;
945 for (; (prgbx <= prgbx_end) && (pyuv <= pyuv_end) && (w < ww) ;) {
946 IUYVY2RGBX_8(pyuv, prgbx, 0, 0);
948 prgbx += PIXEL8_RGBX;
954 // compressed format? XXX if only one of the frame in / out has step, this may lead to crash...
955 for (; (prgbx <= prgbx_end) && (pyuv <= pyuv_end) ;) {
956 IUYVY2RGBX_8(pyuv, prgbx, 0, 0);
958 prgbx += PIXEL8_RGBX;
963 for (; (prgbx <= prgbx_end) && (pyuv <= pyuv_end) ;) {
964 IUYVY2RGBX_8(pyuv, prgbx, 0, 0);
966 prgbx += PIXEL8_RGBX;
973 #define IUYVY2BGR_2(pyuv, pbgr, ax, bx) { \
974 const int d0 = (pyuv)[ax+0]; \
975 const int d2 = (pyuv)[ax+2]; \
976 const int r = (22987 * (d2/*(pyuv)[ax+2]*/ - 128)) >> 14; \
977 const int g = (-5636 * (d0/*(pyuv)[ax+0]*/ - 128) - 11698 * (d2/*(pyuv)[ax+2]*/ - 128)) >> 14; \
978 const int b = (29049 * (d0/*(pyuv)[ax+0]*/ - 128)) >> 14; \
979 const int y1 = (pyuv)[ax+1]; \
980 (pbgr)[bx+0] = sat(y1 + b); \
981 (pbgr)[bx+1] = sat(y1 + g); \
982 (pbgr)[bx+2] = sat(y1 + r); \
983 const int y3 = (pyuv)[ax+3]; \
984 (pbgr)[bx+3] = sat(y3 + b); \
985 (pbgr)[bx+4] = sat(y3 + g); \
986 (pbgr)[bx+5] = sat(y3 + r); \
988 #define IUYVY2BGR_16(pyuv, pbgr, ax, bx) \
989 IUYVY2BGR_8(pyuv, pbgr, ax, bx) \
990 IUYVY2BGR_8(pyuv, pbgr, ax + PIXEL8_UYVY, bx + PIXEL8_BGR)
991 #define IUYVY2BGR_8(pyuv, pbgr, ax, bx) \
992 IUYVY2BGR_4(pyuv, pbgr, ax, bx) \
993 IUYVY2BGR_4(pyuv, pbgr, ax + PIXEL4_UYVY, bx + PIXEL4_BGR)
994 #define IUYVY2BGR_4(pyuv, pbgr, ax, bx) \
995 IUYVY2BGR_2(pyuv, pbgr, ax, bx) \
996 IUYVY2BGR_2(pyuv, pbgr, ax + PIXEL2_UYVY, bx + PIXEL2_BGR)
998 /** @brief Convert a frame from UYVY to BGR888
1000 * @param ini UYVY frame
1001 * @param out BGR888 frame
1003 uvc_error_t uvc_uyvy2bgr(uvc_frame_t *in, uvc_frame_t *out) {
1004 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_UYVY))
1005 return UVC_ERROR_INVALID_PARAM;
1007 if (UNLIKELY(uvc_ensure_frame_size(out, in->width * in->height * PIXEL_BGR) < 0))
1008 return UVC_ERROR_NO_MEM;
1010 out->width = in->width;
1011 out->height = in->height;
1012 out->frame_format = UVC_FRAME_FORMAT_BGR;
1013 if (out->library_owns_data)
1014 out->step = in->width * PIXEL_BGR;
1015 out->sequence = in->sequence;
1016 out->capture_time = in->capture_time;
1017 out->source = in->source;
1019 uint8_t *pyuv = in->data;
1020 const uint8_t *pyuv_end = pyuv + in->data_bytes - PIXEL8_UYVY;
1021 uint8_t *pbgr = out->data;
1022 const uint8_t *pbgr_end = pbgr + out->data_bytes - PIXEL8_BGR;
1026 if (in->step && out->step && (in->step != out->step)) {
1027 const int hh = in->height < out->height ? in->height : out->height;
1028 const int ww = in->width < out->width ? in->width : out->width;
1030 for (h = 0; h < hh; h++) {
1032 pyuv = in->data + in->step * h;
1033 pbgr = out->data + out->step * h;
1034 for (; (pbgr <= pbgr_end) && (pyuv <= pyuv_end) && (w < ww) ;) {
1035 IUYVY2BGR_8(pyuv, pbgr, 0, 0);
1038 pyuv += PIXEL8_UYVY;
1043 // compressed format? XXX if only one of the frame in / out has step, this may lead to crash...
1044 for (; (pbgr <= pbgr_end) && (pyuv <= pyuv_end) ;) {
1045 IUYVY2BGR_8(pyuv, pbgr, 0, 0);
1048 pyuv += PIXEL8_UYVY;
1052 for (; (pbgr <= pbgr_end) && (pyuv <= pyuv_end) ;) {
1053 IUYVY2BGR_8(pyuv, pbgr, 0, 0);
1056 pyuv += PIXEL8_UYVY;
1062 int uvc_yuyv2yuv420P(uvc_frame_t *in, uvc_frame_t *out) {
1066 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_YUYV))
1067 RETURN(UVC_ERROR_INVALID_PARAM, uvc_error_t);
1069 if (UNLIKELY(uvc_ensure_frame_size(out, (in->width * in->height * 3) / 2) < 0))
1070 RETURN(UVC_ERROR_NO_MEM, uvc_error_t);
1072 const uint8_t *src = in->data;
1073 uint8_t *dest = out->data;
1074 const int32_t width = in->width;
1075 const int32_t height = in->height;
1076 const int32_t src_width = in->step;
1077 const int32_t src_height = in->height;
1078 const int32_t dest_width = out->width = out->step = in->width;
1079 const int32_t dest_height = out->height = in->height;
1080 const uint32_t hh = src_height < dest_height ? src_height : dest_height;
1082 uint8_t *v = dest + dest_width * dest_height;
1083 uint8_t *u = dest + dest_width * dest_height * 5 / 4;
1085 for (h = 0; h < hh; h++) {
1086 const uint8_t *yuv = src + src_width * h;
1087 for (w = 0; w < width; w += 4) {
1088 *(y++) = yuv[0]; // y
1089 *(y++) = yuv[2]; // y'
1090 *(y++) = yuv[4]; // y''
1091 *(y++) = yuv[6]; // y'''
1093 *(u++) = yuv[3]; // u
1094 *(u++) = yuv[7]; // u
1096 *(v++) = yuv[1]; // v
1097 *(v++) = yuv[5]; // v
1099 yuv += 8; // (1pixel=2bytes)x4pixel=8bytes
1105 //--------------------------------------------------------------------------------
1106 int uvc_yuyv2iyuv420P(uvc_frame_t *in, uvc_frame_t *out) {
1110 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_YUYV))
1111 RETURN(UVC_ERROR_INVALID_PARAM, uvc_error_t);
1113 if (UNLIKELY(uvc_ensure_frame_size(out, (in->width * in->height * 3) / 2) < 0))
1114 RETURN(UVC_ERROR_NO_MEM, uvc_error_t);
1116 const uint8_t *src = in->data;
1117 uint8_t *dest = out->data;
1118 const int32_t width = in->width;
1119 const int32_t height = in->height;
1120 const int32_t src_width = in->step;
1121 const int32_t src_height = in->height;
1122 const int32_t dest_width = out->width = out->step = in->width;
1123 const int32_t dest_height = out->height = in->height;
1124 const uint32_t hh = src_height < dest_height ? src_height : dest_height;
1126 uint8_t *u = dest + dest_width * dest_height * 5 / 4;
1127 uint8_t *v = dest + dest_width * dest_height * 5 / 4;
1129 for (h = 0; h < hh; h++) {
1130 const uint8_t *yuv = src + src_width * h;
1131 for (w = 0; w < width; w += 4) {
1132 *(y++) = yuv[0]; // y
1133 *(y++) = yuv[2]; // y'
1134 *(y++) = yuv[4]; // y''
1135 *(y++) = yuv[6]; // y'''
1137 *(u++) = yuv[3]; // u
1138 *(u++) = yuv[7]; // u
1140 *(v++) = yuv[1]; // v
1141 *(v++) = yuv[5]; // v
1143 yuv += 8; // (1pixel=2bytes)x4pixel=8bytes
1149 uvc_error_t uvc_yuyv2yuv420SP(uvc_frame_t *in, uvc_frame_t *out) {
1152 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_YUYV))
1153 RETURN(UVC_ERROR_INVALID_PARAM, uvc_error_t);
1155 if (UNLIKELY(uvc_ensure_frame_size(out, (in->width * in->height * 3) / 2) < 0))
1156 RETURN(UVC_ERROR_NO_MEM, uvc_error_t);
1158 const uint8_t *src = in->data;
1159 uint8_t *dest = out->data;
1160 const int32_t width = in->width;
1161 const int32_t height = in->height;
1162 const int32_t src_width = in->step;
1163 const int32_t src_height = in->height;
1164 const int32_t dest_width = out->width = out->step = in->width;
1165 const int32_t dest_height = out->height = in->height;
1167 const uint32_t hh = src_height < dest_height ? src_height : dest_height;
1168 uint8_t *uv = dest + dest_width * dest_height;
1170 for (h = 0; h < hh - 1; h += 2) {
1171 uint8_t *y0 = dest + width * h;
1172 uint8_t *y1 = y0 + width;
1173 const uint8_t *yuv = src + src_width * h;
1174 for (w = 0; w < width; w += 4) {
1175 *(y0++) = yuv[0]; // y
1176 *(y0++) = yuv[2]; // y'
1177 *(y0++) = yuv[4]; // y''
1178 *(y0++) = yuv[6]; // y'''
1179 *(uv++) = yuv[1]; // u
1180 *(uv++) = yuv[3]; // v
1181 *(uv++) = yuv[5]; // u
1182 *(uv++) = yuv[7]; // v
1183 *(y1++) = yuv[src_width+0]; // y on next low
1184 *(y1++) = yuv[src_width+2]; // y' on next low
1185 *(y1++) = yuv[src_width+4]; // y'' on next low
1186 *(y1++) = yuv[src_width+6]; // y''' on next low
1187 yuv += 8; // (1pixel=2bytes)x4pixels=8bytes
1191 RETURN(UVC_SUCCESS, uvc_error_t);
1194 uvc_error_t uvc_yuyv2iyuv420SP(uvc_frame_t *in, uvc_frame_t *out) {
1197 if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_YUYV))
1198 RETURN(UVC_ERROR_INVALID_PARAM, uvc_error_t);
1200 if (UNLIKELY(uvc_ensure_frame_size(out, (in->width * in->height * 3) / 2) < 0))
1201 return UVC_ERROR_NO_MEM;
1203 const uint8_t *src = in->data;
1204 uint8_t *dest =out->data;
1205 const int32_t width = in->width;
1206 const int32_t height = in->height;
1207 const int32_t src_width = in->step;
1208 const int32_t src_height = in->height;
1209 const int32_t dest_width = out->width = out->step = in->width;
1210 const int32_t dest_height = out->height = in->height;
1212 const uint32_t hh = src_height < dest_height ? src_height : dest_height;
1213 uint8_t *uv = dest + dest_width * dest_height;
1215 for (h = 0; h < hh - 1; h += 2) {
1216 uint8_t *y0 = dest + width * h;
1217 uint8_t *y1 = y0 + width;
1218 const uint8_t *yuv = src + src_width * h;
1219 for (w = 0; w < width; w += 4) {
1220 *(y0++) = yuv[0]; // y
1221 *(y0++) = yuv[2]; // y'
1222 *(y0++) = yuv[4]; // y''
1223 *(y0++) = yuv[6]; // y'''
1224 *(uv++) = yuv[3]; // v
1225 *(uv++) = yuv[1]; // u
1226 *(uv++) = yuv[7]; // v
1227 *(uv++) = yuv[5]; // u
1228 *(y1++) = yuv[src_width+0]; // y on next low
1229 *(y1++) = yuv[src_width+2]; // y' on next low
1230 *(y1++) = yuv[src_width+4]; // y'' on next low
1231 *(y1++) = yuv[src_width+6]; // y''' on next low
1232 yuv += 8; // (1pixel=2bytes)x4pixels=8bytes
1236 RETURN(UVC_SUCCESS, uvc_error_t);
1239 /** @brief Convert a frame to RGB565
1242 * @param in non-RGB565 frame
1243 * @param out RGB565 frame
1245 uvc_error_t uvc_any2rgb565(uvc_frame_t *in, uvc_frame_t *out) {
1247 switch (in->frame_format) {
1248 #ifdef LIBUVC_HAS_JPEG
1249 case UVC_FRAME_FORMAT_MJPEG:
1250 return uvc_mjpeg2rgb565(in, out);
1252 case UVC_FRAME_FORMAT_YUYV:
1253 return uvc_yuyv2rgb565(in, out);
1254 case UVC_FRAME_FORMAT_UYVY:
1255 return uvc_uyvy2rgb565(in, out);
1256 case UVC_FRAME_FORMAT_RGB565:
1257 return uvc_duplicate_frame(in, out);
1258 case UVC_FRAME_FORMAT_RGB:
1259 return uvc_rgb2rgb565(in, out);
1261 return UVC_ERROR_NOT_SUPPORTED;
1265 /** @brief Convert a frame to RGB888
1268 * @param in non-RGB888 frame
1269 * @param out RGB888 frame
1271 uvc_error_t uvc_any2rgb(uvc_frame_t *in, uvc_frame_t *out) {
1273 switch (in->frame_format) {
1274 #ifdef LIBUVC_HAS_JPEG
1275 case UVC_FRAME_FORMAT_MJPEG:
1276 return uvc_mjpeg2rgb(in, out);
1278 case UVC_FRAME_FORMAT_YUYV:
1279 return uvc_yuyv2rgb(in, out);
1280 case UVC_FRAME_FORMAT_UYVY:
1281 return uvc_uyvy2rgb(in, out);
1282 case UVC_FRAME_FORMAT_RGB:
1283 return uvc_duplicate_frame(in, out);
1285 return UVC_ERROR_NOT_SUPPORTED;
1289 /** @brief Convert a frame to BGR888
1292 * @param in non-BGR888 frame
1293 * @param out BGR888 frame
1295 uvc_error_t uvc_any2bgr(uvc_frame_t *in, uvc_frame_t *out) {
1297 switch (in->frame_format) {
1298 #ifdef LIBUVC_HAS_JPEG
1299 case UVC_FRAME_FORMAT_MJPEG:
1300 return uvc_mjpeg2bgr(in, out);
1302 case UVC_FRAME_FORMAT_YUYV:
1303 return uvc_yuyv2bgr(in, out);
1304 case UVC_FRAME_FORMAT_UYVY:
1305 return uvc_uyvy2bgr(in, out);
1306 case UVC_FRAME_FORMAT_BGR:
1307 return uvc_duplicate_frame(in, out);
1309 return UVC_ERROR_NOT_SUPPORTED;
1313 /** @brief Convert a frame to RGBX8888
1316 * @param in non-rgbx frame
1317 * @param out rgbx frame
1319 uvc_error_t uvc_any2rgbx(uvc_frame_t *in, uvc_frame_t *out) {
1321 switch (in->frame_format) {
1322 #ifdef LIBUVC_HAS_JPEG
1323 case UVC_FRAME_FORMAT_MJPEG:
1324 return uvc_mjpeg2rgbx(in, out);
1326 case UVC_FRAME_FORMAT_YUYV:
1327 return uvc_yuyv2rgbx(in, out);
1328 case UVC_FRAME_FORMAT_UYVY:
1329 return uvc_uyvy2rgbx(in, out);
1330 case UVC_FRAME_FORMAT_RGBX:
1331 return uvc_duplicate_frame(in, out);
1332 case UVC_FRAME_FORMAT_RGB:
1333 return uvc_rgb2rgbx(in, out);
1335 return UVC_ERROR_NOT_SUPPORTED;
1339 /** @brief Convert a frame to yuyv
1342 * @param in non-yuyv frame
1343 * @param out yuyv frame
1345 uvc_error_t uvc_any2yuyv(uvc_frame_t *in, uvc_frame_t *out) {
1347 switch (in->frame_format) {
1348 #ifdef LIBUVC_HAS_JPEG
1349 case UVC_FRAME_FORMAT_MJPEG:
1350 return uvc_mjpeg2yuyv(in, out);
1352 case UVC_FRAME_FORMAT_YUYV:
1353 return uvc_duplicate_frame(in, out);
1355 return UVC_ERROR_NOT_SUPPORTED;
1359 /** @brief Convert a frame to yuv420sp
1362 * @param in non-yuv420sp frame
1363 * @param out yuv420sp frame
1365 uvc_error_t uvc_any2yuv420SP(uvc_frame_t *in, uvc_frame_t *out) {
1366 uvc_error_t result = UVC_ERROR_NO_MEM;
1367 uvc_frame_t *yuv = uvc_allocate_frame((in->width * in->height * 3) / 2);
1369 result = uvc_any2yuyv(in, yuv);
1370 if (LIKELY(!result)) {
1371 result = uvc_yuyv2yuv420SP(yuv, out);
1373 uvc_free_frame(yuv);
1378 /** @brief Convert a frame to iyuv420sp(NV21)
1381 * @param in non-iyuv420SP(NV21) frame
1382 * @param out iyuv420SP(NV21) frame
1384 uvc_error_t uvc_any2iyuv420SP(uvc_frame_t *in, uvc_frame_t *out) {
1385 uvc_error_t result = UVC_ERROR_NO_MEM;
1386 uvc_frame_t *yuv = uvc_allocate_frame((in->width * in->height * 3) / 2);
1388 result = uvc_any2yuyv(in, yuv);
1389 if (LIKELY(!result)) {
1390 result = uvc_yuyv2iyuv420SP(yuv, out);
1392 uvc_free_frame(yuv);