1 /*********************************************************************
2 * Software License Agreement (BSD License)
4 * Copyright (C) 2010-2012 Ken Tossell
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the author nor other contributors may be
18 * used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
35 * @defgroup frame Frame processing
36 * @brief Tools for managing frame buffers and converting between image formats
38 #include "libuvc/libuvc.h"
39 #include "libuvc/libuvc_internal.h"
42 uvc_error_t uvc_ensure_frame_size(uvc_frame_t *frame, size_t need_bytes) {
43 if (frame->library_owns_data) {
44 if (!frame->data || frame->data_bytes != need_bytes) {
45 frame->data_bytes = need_bytes;
46 frame->data = realloc(frame->data, frame->data_bytes);
49 return UVC_ERROR_NO_MEM;
52 if (!frame->data || frame->data_bytes < need_bytes)
53 return UVC_ERROR_NO_MEM;
58 /** @brief Allocate a frame structure
61 * @param data_bytes Number of bytes to allocate, or zero
62 * @return New frame, or NULL on error
64 uvc_frame_t *uvc_allocate_frame(size_t data_bytes) {
65 uvc_frame_t *frame = malloc(sizeof(*frame));
70 memset(frame, 0, sizeof(*frame));
72 frame->library_owns_data = 1;
75 frame->data_bytes = data_bytes;
76 frame->data = malloc(data_bytes);
87 /** @brief Free a frame structure
90 * @param frame Frame to destroy
92 void uvc_free_frame(uvc_frame_t *frame) {
93 if (frame->data_bytes > 0 && frame->library_owns_data)
99 static inline unsigned char sat(int i) {
100 return (unsigned char)( i >= 255 ? 255 : (i < 0 ? 0 : i));
103 /** @brief Duplicate a frame, preserving color format
106 * @param in Original frame
107 * @param out Duplicate frame
109 uvc_error_t uvc_duplicate_frame(uvc_frame_t *in, uvc_frame_t *out) {
110 if (uvc_ensure_frame_size(out, in->data_bytes) < 0)
111 return UVC_ERROR_NO_MEM;
113 out->width = in->width;
114 out->height = in->height;
115 out->frame_format = in->frame_format;
116 out->step = in->step;
117 out->sequence = in->sequence;
118 out->capture_time = in->capture_time;
119 out->source = in->source;
121 memcpy(out->data, in->data, in->data_bytes);
126 #define YUYV2RGB_2(pyuv, prgb) { \
127 float r = 1.402f * ((pyuv)[3]-128); \
128 float g = -0.34414f * ((pyuv)[1]-128) - 0.71414f * ((pyuv)[3]-128); \
129 float b = 1.772f * ((pyuv)[1]-128); \
130 (prgb)[0] = sat(pyuv[0] + r); \
131 (prgb)[1] = sat(pyuv[0] + g); \
132 (prgb)[2] = sat(pyuv[0] + b); \
133 (prgb)[3] = sat(pyuv[2] + r); \
134 (prgb)[4] = sat(pyuv[2] + g); \
135 (prgb)[5] = sat(pyuv[2] + b); \
137 #define IYUYV2RGB_2(pyuv, prgb) { \
138 int r = (22987 * ((pyuv)[3] - 128)) >> 14; \
139 int g = (-5636 * ((pyuv)[1] - 128) - 11698 * ((pyuv)[3] - 128)) >> 14; \
140 int b = (29049 * ((pyuv)[1] - 128)) >> 14; \
141 (prgb)[0] = sat(*(pyuv) + r); \
142 (prgb)[1] = sat(*(pyuv) + g); \
143 (prgb)[2] = sat(*(pyuv) + b); \
144 (prgb)[3] = sat((pyuv)[2] + r); \
145 (prgb)[4] = sat((pyuv)[2] + g); \
146 (prgb)[5] = sat((pyuv)[2] + b); \
148 #define IYUYV2RGB_16(pyuv, prgb) IYUYV2RGB_8(pyuv, prgb); IYUYV2RGB_8(pyuv + 16, prgb + 24);
149 #define IYUYV2RGB_8(pyuv, prgb) IYUYV2RGB_4(pyuv, prgb); IYUYV2RGB_4(pyuv + 8, prgb + 12);
150 #define IYUYV2RGB_4(pyuv, prgb) IYUYV2RGB_2(pyuv, prgb); IYUYV2RGB_2(pyuv + 4, prgb + 6);
152 /** @brief Convert a frame from YUYV to RGB
155 * @param in YUYV frame
156 * @param out RGB frame
158 uvc_error_t uvc_yuyv2rgb(uvc_frame_t *in, uvc_frame_t *out) {
159 if (in->frame_format != UVC_FRAME_FORMAT_YUYV)
160 return UVC_ERROR_INVALID_PARAM;
162 if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
163 return UVC_ERROR_NO_MEM;
165 out->width = in->width;
166 out->height = in->height;
167 out->frame_format = UVC_FRAME_FORMAT_RGB;
168 out->step = in->width * 3;
169 out->sequence = in->sequence;
170 out->capture_time = in->capture_time;
171 out->source = in->source;
173 uint8_t *pyuv = in->data;
174 uint8_t *prgb = out->data;
175 uint8_t *prgb_end = prgb + out->data_bytes;
177 while (prgb < prgb_end) {
178 IYUYV2RGB_8(pyuv, prgb);
187 #define IYUYV2BGR_2(pyuv, pbgr) { \
188 int r = (22987 * ((pyuv)[3] - 128)) >> 14; \
189 int g = (-5636 * ((pyuv)[1] - 128) - 11698 * ((pyuv)[3] - 128)) >> 14; \
190 int b = (29049 * ((pyuv)[1] - 128)) >> 14; \
191 (pbgr)[0] = sat(*(pyuv) + b); \
192 (pbgr)[1] = sat(*(pyuv) + g); \
193 (pbgr)[2] = sat(*(pyuv) + r); \
194 (pbgr)[3] = sat((pyuv)[2] + b); \
195 (pbgr)[4] = sat((pyuv)[2] + g); \
196 (pbgr)[5] = sat((pyuv)[2] + r); \
198 #define IYUYV2BGR_16(pyuv, pbgr) IYUYV2BGR_8(pyuv, pbgr); IYUYV2BGR_8(pyuv + 16, pbgr + 24);
199 #define IYUYV2BGR_8(pyuv, pbgr) IYUYV2BGR_4(pyuv, pbgr); IYUYV2BGR_4(pyuv + 8, pbgr + 12);
200 #define IYUYV2BGR_4(pyuv, pbgr) IYUYV2BGR_2(pyuv, pbgr); IYUYV2BGR_2(pyuv + 4, pbgr + 6);
202 /** @brief Convert a frame from YUYV to BGR
205 * @param in YUYV frame
206 * @param out BGR frame
208 uvc_error_t uvc_yuyv2bgr(uvc_frame_t *in, uvc_frame_t *out) {
209 if (in->frame_format != UVC_FRAME_FORMAT_YUYV)
210 return UVC_ERROR_INVALID_PARAM;
212 if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
213 return UVC_ERROR_NO_MEM;
215 out->width = in->width;
216 out->height = in->height;
217 out->frame_format = UVC_FRAME_FORMAT_BGR;
218 out->step = in->width * 3;
219 out->sequence = in->sequence;
220 out->capture_time = in->capture_time;
221 out->source = in->source;
223 uint8_t *pyuv = in->data;
224 uint8_t *pbgr = out->data;
225 uint8_t *pbgr_end = pbgr + out->data_bytes;
227 while (pbgr < pbgr_end) {
228 IYUYV2BGR_8(pyuv, pbgr);
237 #define IYUYV2Y(pyuv, py) { \
238 (py)[0] = (pyuv[0]); \
241 /** @brief Convert a frame from YUYV to Y (GRAY8)
244 * @param in YUYV frame
245 * @param out GRAY8 frame
247 uvc_error_t uvc_yuyv2y(uvc_frame_t *in, uvc_frame_t *out) {
248 if (in->frame_format != UVC_FRAME_FORMAT_YUYV)
249 return UVC_ERROR_INVALID_PARAM;
251 if (uvc_ensure_frame_size(out, in->width * in->height) < 0)
252 return UVC_ERROR_NO_MEM;
254 out->width = in->width;
255 out->height = in->height;
256 out->frame_format = UVC_FRAME_FORMAT_GRAY8;
257 out->step = in->width;
258 out->sequence = in->sequence;
259 out->capture_time = in->capture_time;
260 out->source = in->source;
262 uint8_t *pyuv = in->data;
263 uint8_t *py = out->data;
264 uint8_t *py_end = py + out->data_bytes;
266 while (py < py_end) {
276 #define IYUYV2UV(pyuv, puv) { \
277 (puv)[0] = (pyuv[1]); \
280 /** @brief Convert a frame from YUYV to UV (GRAY8)
283 * @param in YUYV frame
284 * @param out GRAY8 frame
286 uvc_error_t uvc_yuyv2uv(uvc_frame_t *in, uvc_frame_t *out) {
287 if (in->frame_format != UVC_FRAME_FORMAT_YUYV)
288 return UVC_ERROR_INVALID_PARAM;
290 if (uvc_ensure_frame_size(out, in->width * in->height) < 0)
291 return UVC_ERROR_NO_MEM;
293 out->width = in->width;
294 out->height = in->height;
295 out->frame_format = UVC_FRAME_FORMAT_GRAY8;
296 out->step = in->width;
297 out->sequence = in->sequence;
298 out->capture_time = in->capture_time;
299 out->source = in->source;
301 uint8_t *pyuv = in->data;
302 uint8_t *puv = out->data;
303 uint8_t *puv_end = puv + out->data_bytes;
305 while (puv < puv_end) {
315 #define IUYVY2RGB_2(pyuv, prgb) { \
316 int r = (22987 * ((pyuv)[2] - 128)) >> 14; \
317 int g = (-5636 * ((pyuv)[0] - 128) - 11698 * ((pyuv)[2] - 128)) >> 14; \
318 int b = (29049 * ((pyuv)[0] - 128)) >> 14; \
319 (prgb)[0] = sat((pyuv)[1] + r); \
320 (prgb)[1] = sat((pyuv)[1] + g); \
321 (prgb)[2] = sat((pyuv)[1] + b); \
322 (prgb)[3] = sat((pyuv)[3] + r); \
323 (prgb)[4] = sat((pyuv)[3] + g); \
324 (prgb)[5] = sat((pyuv)[3] + b); \
326 #define IUYVY2RGB_16(pyuv, prgb) IUYVY2RGB_8(pyuv, prgb); IUYVY2RGB_8(pyuv + 16, prgb + 24);
327 #define IUYVY2RGB_8(pyuv, prgb) IUYVY2RGB_4(pyuv, prgb); IUYVY2RGB_4(pyuv + 8, prgb + 12);
328 #define IUYVY2RGB_4(pyuv, prgb) IUYVY2RGB_2(pyuv, prgb); IUYVY2RGB_2(pyuv + 4, prgb + 6);
330 /** @brief Convert a frame from UYVY to RGB
332 * @param ini UYVY frame
333 * @param out RGB frame
335 uvc_error_t uvc_uyvy2rgb(uvc_frame_t *in, uvc_frame_t *out) {
336 if (in->frame_format != UVC_FRAME_FORMAT_UYVY)
337 return UVC_ERROR_INVALID_PARAM;
339 if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
340 return UVC_ERROR_NO_MEM;
342 out->width = in->width;
343 out->height = in->height;
344 out->frame_format = UVC_FRAME_FORMAT_RGB;
345 out->step = in->width *3;
346 out->sequence = in->sequence;
347 out->capture_time = in->capture_time;
348 out->source = in->source;
350 uint8_t *pyuv = in->data;
351 uint8_t *prgb = out->data;
352 uint8_t *prgb_end = prgb + out->data_bytes;
354 while (prgb < prgb_end) {
355 IUYVY2RGB_8(pyuv, prgb);
364 #define IUYVY2BGR_2(pyuv, pbgr) { \
365 int r = (22987 * ((pyuv)[2] - 128)) >> 14; \
366 int g = (-5636 * ((pyuv)[0] - 128) - 11698 * ((pyuv)[2] - 128)) >> 14; \
367 int b = (29049 * ((pyuv)[0] - 128)) >> 14; \
368 (pbgr)[0] = sat((pyuv)[1] + b); \
369 (pbgr)[1] = sat((pyuv)[1] + g); \
370 (pbgr)[2] = sat((pyuv)[1] + r); \
371 (pbgr)[3] = sat((pyuv)[3] + b); \
372 (pbgr)[4] = sat((pyuv)[3] + g); \
373 (pbgr)[5] = sat((pyuv)[3] + r); \
375 #define IUYVY2BGR_16(pyuv, pbgr) IUYVY2BGR_8(pyuv, pbgr); IUYVY2BGR_8(pyuv + 16, pbgr + 24);
376 #define IUYVY2BGR_8(pyuv, pbgr) IUYVY2BGR_4(pyuv, pbgr); IUYVY2BGR_4(pyuv + 8, pbgr + 12);
377 #define IUYVY2BGR_4(pyuv, pbgr) IUYVY2BGR_2(pyuv, pbgr); IUYVY2BGR_2(pyuv + 4, pbgr + 6);
379 /** @brief Convert a frame from UYVY to BGR
381 * @param ini UYVY frame
382 * @param out BGR frame
384 uvc_error_t uvc_uyvy2bgr(uvc_frame_t *in, uvc_frame_t *out) {
385 if (in->frame_format != UVC_FRAME_FORMAT_UYVY)
386 return UVC_ERROR_INVALID_PARAM;
388 if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
389 return UVC_ERROR_NO_MEM;
391 out->width = in->width;
392 out->height = in->height;
393 out->frame_format = UVC_FRAME_FORMAT_BGR;
394 out->step = in->width *3;
395 out->sequence = in->sequence;
396 out->capture_time = in->capture_time;
397 out->source = in->source;
399 uint8_t *pyuv = in->data;
400 uint8_t *pbgr = out->data;
401 uint8_t *pbgr_end = pbgr + out->data_bytes;
403 while (pbgr < pbgr_end) {
404 IUYVY2BGR_8(pyuv, pbgr);
413 /** @brief Convert a frame to RGB
416 * @param in non-RGB frame
417 * @param out RGB frame
419 uvc_error_t uvc_any2rgb(uvc_frame_t *in, uvc_frame_t *out) {
420 switch (in->frame_format) {
421 case UVC_FRAME_FORMAT_YUYV:
422 return uvc_yuyv2rgb(in, out);
423 case UVC_FRAME_FORMAT_UYVY:
424 return uvc_uyvy2rgb(in, out);
425 case UVC_FRAME_FORMAT_RGB:
426 return uvc_duplicate_frame(in, out);
428 return UVC_ERROR_NOT_SUPPORTED;
432 /** @brief Convert a frame to BGR
435 * @param in non-BGR frame
436 * @param out BGR frame
438 uvc_error_t uvc_any2bgr(uvc_frame_t *in, uvc_frame_t *out) {
439 switch (in->frame_format) {
440 case UVC_FRAME_FORMAT_YUYV:
441 return uvc_yuyv2bgr(in, out);
442 case UVC_FRAME_FORMAT_UYVY:
443 return uvc_uyvy2bgr(in, out);
444 case UVC_FRAME_FORMAT_BGR:
445 return uvc_duplicate_frame(in, out);
447 return UVC_ERROR_NOT_SUPPORTED;