1 /*
2 # (C) 2008-2011 Hans de Goede <hdegoede@redhat.com>
3
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU Lesser General Public License as published by
6 # the Free Software Foundation; either version 2.1 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17 */
18
19 #include <errno.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include "libv4lconvert.h"
26 #include "libv4lconvert-priv.h"
27 #include "libv4lsyscall-priv.h"
28
29 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
30 #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
31 #define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
32
set_bit(int nr,volatile unsigned long * addr)33 static inline void set_bit(int nr, volatile unsigned long *addr)
34 {
35 unsigned long mask = BIT_MASK(nr);
36 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
37
38 *p |= mask;
39 }
40
clear_bit(int nr,volatile unsigned long * addr)41 static inline void clear_bit(int nr, volatile unsigned long *addr)
42 {
43 unsigned long mask = BIT_MASK(nr);
44 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
45
46 *p &= ~mask;
47 }
48
test_bit(int nr,const volatile unsigned long * addr)49 static inline int test_bit(int nr, const volatile unsigned long *addr)
50 {
51 return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
52 }
53
dev_init(int fd)54 static void *dev_init(int fd)
55 {
56 return NULL;
57 }
58
dev_close(void * dev_ops_priv)59 static void dev_close(void *dev_ops_priv)
60 {
61 }
62
dev_ioctl(void * dev_ops_priv,int fd,unsigned long cmd,void * arg)63 static int dev_ioctl(void *dev_ops_priv, int fd, unsigned long cmd, void *arg)
64 {
65 return SYS_IOCTL(fd, cmd, arg);
66 }
67
dev_read(void * dev_ops_priv,int fd,void * buf,size_t len)68 static ssize_t dev_read(void *dev_ops_priv, int fd, void *buf, size_t len)
69 {
70 return SYS_READ(fd, buf, len);
71 }
72
dev_write(void * dev_ops_priv,int fd,const void * buf,size_t len)73 static ssize_t dev_write(void *dev_ops_priv, int fd, const void *buf,
74 size_t len)
75 {
76 return SYS_WRITE(fd, buf, len);
77 }
78
79 static const struct libv4l_dev_ops default_dev_ops = {
80 .init = dev_init,
81 .close = dev_close,
82 .ioctl = dev_ioctl,
83 .read = dev_read,
84 .write = dev_write,
85 };
86
v4lconvert_get_default_dev_ops()87 const struct libv4l_dev_ops *v4lconvert_get_default_dev_ops()
88 {
89 return &default_dev_ops;
90 }
91
92 static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
93 unsigned int pixelformat, int index);
94
95 /*
96 * Notes:
97 * 1) for proper functioning of v4lconvert_enum_fmt the first entries in
98 * supported_src_pixfmts must match with the entries in
99 * supported_dst_pixfmts.
100 * 2) The field needs_conversion should be zero, *except* for device-specific
101 * formats, where it doesn't make sense for applications to have their
102 * own decoders.
103 */
104 #define SUPPORTED_DST_PIXFMTS \
105 /* fourcc bpp rgb yuv needs */ \
106 /* rank rank conversion */ \
107 { V4L2_PIX_FMT_RGB24, 24, 1, 5, 0 }, \
108 { V4L2_PIX_FMT_BGR24, 24, 1, 5, 0 }, \
109 { V4L2_PIX_FMT_YUV420, 12, 6, 1, 0 }, \
110 { V4L2_PIX_FMT_YVU420, 12, 6, 1, 0 }
111
112 static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
113 SUPPORTED_DST_PIXFMTS,
114 /* packed rgb formats */
115 { V4L2_PIX_FMT_RGB565, 16, 4, 6, 0 },
116 { V4L2_PIX_FMT_BGR32, 32, 4, 6, 0 },
117 { V4L2_PIX_FMT_RGB32, 32, 4, 6, 0 },
118 { V4L2_PIX_FMT_XBGR32, 32, 4, 6, 0 },
119 { V4L2_PIX_FMT_XRGB32, 32, 4, 6, 0 },
120 { V4L2_PIX_FMT_ABGR32, 32, 4, 6, 0 },
121 { V4L2_PIX_FMT_ARGB32, 32, 4, 6, 0 },
122 /* yuv 4:2:2 formats */
123 { V4L2_PIX_FMT_YUYV, 16, 5, 4, 0 },
124 { V4L2_PIX_FMT_YVYU, 16, 5, 4, 0 },
125 { V4L2_PIX_FMT_UYVY, 16, 5, 4, 0 },
126 { V4L2_PIX_FMT_NV16, 16, 5, 4, 1 },
127 { V4L2_PIX_FMT_NV61, 16, 5, 4, 1 },
128 /* yuv 4:2:0 formats */
129 { V4L2_PIX_FMT_SPCA501, 12, 6, 3, 1 },
130 { V4L2_PIX_FMT_SPCA505, 12, 6, 3, 1 },
131 { V4L2_PIX_FMT_SPCA508, 12, 6, 3, 1 },
132 { V4L2_PIX_FMT_CIT_YYVYUY, 12, 6, 3, 1 },
133 { V4L2_PIX_FMT_KONICA420, 12, 6, 3, 1 },
134 { V4L2_PIX_FMT_SN9C20X_I420, 12, 6, 3, 1 },
135 { V4L2_PIX_FMT_M420, 12, 6, 3, 1 },
136 { V4L2_PIX_FMT_NV12_16L16, 12, 6, 3, 1 },
137 { V4L2_PIX_FMT_NV12, 12, 6, 3, 1 },
138 { V4L2_PIX_FMT_CPIA1, 0, 6, 3, 1 },
139 /* JPEG and variants */
140 { V4L2_PIX_FMT_MJPEG, 0, 7, 7, 0 },
141 { V4L2_PIX_FMT_JPEG, 0, 7, 7, 0 },
142 { V4L2_PIX_FMT_PJPG, 0, 7, 7, 1 },
143 { V4L2_PIX_FMT_JPGL, 0, 7, 7, 1 },
144 #ifdef HAVE_LIBV4LCONVERT_HELPERS
145 { V4L2_PIX_FMT_OV511, 0, 7, 7, 1 },
146 { V4L2_PIX_FMT_OV518, 0, 7, 7, 1 },
147 #endif
148 /* uncompressed bayer */
149 { V4L2_PIX_FMT_SBGGR8, 8, 8, 8, 0 },
150 { V4L2_PIX_FMT_SGBRG8, 8, 8, 8, 0 },
151 { V4L2_PIX_FMT_SGRBG8, 8, 8, 8, 0 },
152 { V4L2_PIX_FMT_SRGGB8, 8, 8, 8, 0 },
153 { V4L2_PIX_FMT_STV0680, 8, 8, 8, 1 },
154 { V4L2_PIX_FMT_SBGGR10P, 10, 8, 8, 1 },
155 { V4L2_PIX_FMT_SGBRG10P, 10, 8, 8, 1 },
156 { V4L2_PIX_FMT_SGRBG10P, 10, 8, 8, 1 },
157 { V4L2_PIX_FMT_SRGGB10P, 10, 8, 8, 1 },
158 { V4L2_PIX_FMT_SBGGR10, 16, 8, 8, 1 },
159 { V4L2_PIX_FMT_SGBRG10, 16, 8, 8, 1 },
160 { V4L2_PIX_FMT_SGRBG10, 16, 8, 8, 1 },
161 { V4L2_PIX_FMT_SRGGB10, 16, 8, 8, 1 },
162 { V4L2_PIX_FMT_SBGGR16, 16, 8, 8, 1 },
163 { V4L2_PIX_FMT_SGBRG16, 16, 8, 8, 1 },
164 { V4L2_PIX_FMT_SGRBG16, 16, 8, 8, 1 },
165 { V4L2_PIX_FMT_SRGGB16, 16, 8, 8, 1 },
166 /* compressed bayer */
167 { V4L2_PIX_FMT_SPCA561, 0, 9, 9, 1 },
168 { V4L2_PIX_FMT_SN9C10X, 0, 9, 9, 1 },
169 { V4L2_PIX_FMT_SN9C2028, 0, 9, 9, 1 },
170 { V4L2_PIX_FMT_PAC207, 0, 9, 9, 1 },
171 { V4L2_PIX_FMT_MR97310A, 0, 9, 9, 1 },
172 #ifdef HAVE_JPEG
173 { V4L2_PIX_FMT_JL2005BCD, 0, 9, 9, 1 },
174 #endif
175 { V4L2_PIX_FMT_SQ905C, 0, 9, 9, 1 },
176 /* special */
177 { V4L2_PIX_FMT_SE401, 0, 8, 9, 1 },
178 /* grey formats */
179 { V4L2_PIX_FMT_GREY, 8, 20, 20, 0 },
180 { V4L2_PIX_FMT_Y4, 8, 20, 20, 0 },
181 { V4L2_PIX_FMT_Y6, 8, 20, 20, 0 },
182 { V4L2_PIX_FMT_Y10BPACK, 10, 20, 20, 0 },
183 { V4L2_PIX_FMT_Y16, 16, 20, 20, 0 },
184 { V4L2_PIX_FMT_Y16_BE, 16, 20, 20, 0 },
185 /* hsv formats */
186 { V4L2_PIX_FMT_HSV32, 32, 5, 4, 0 },
187 { V4L2_PIX_FMT_HSV24, 24, 5, 4, 0 },
188 };
189
190 static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = {
191 SUPPORTED_DST_PIXFMTS
192 };
193
194 /* List of well known resolutions which we can get by cropping somewhat larger
195 resolutions */
196 static const int v4lconvert_crop_res[][2] = {
197 /* low res VGA resolutions, can be made by software cropping SIF resolutions
198 for cam/drivers which do not support this in hardware */
199 { 320, 240 },
200 { 160, 120 },
201 /* Some CIF cams (with vv6410 sensor) have slightly larger then usual CIF
202 resolutions, make regular CIF resolutions available on these by sw crop */
203 { 352, 288 },
204 { 176, 144 },
205 };
206
v4lconvert_create(int fd)207 struct v4lconvert_data *v4lconvert_create(int fd)
208 {
209 return v4lconvert_create_with_dev_ops(fd, NULL, &default_dev_ops);
210 }
211
v4lconvert_create_with_dev_ops(int fd,void * dev_ops_priv,const struct libv4l_dev_ops * dev_ops)212 struct v4lconvert_data *v4lconvert_create_with_dev_ops(int fd, void *dev_ops_priv,
213 const struct libv4l_dev_ops *dev_ops)
214 {
215 int i, j;
216 struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data));
217 struct v4l2_capability cap;
218 /*
219 * This keeps tracks of device-specific formats for which apps most
220 * likely don't know. If all a driver can offer are proprietary
221 * formats, a conversion is needed anyway. We can thus safely
222 * add software processing controls without much concern about a
223 * performance impact.
224 */
225 int always_needs_conversion = 1;
226
227 if (!data) {
228 fprintf(stderr, "libv4lconvert: error: out of memory!\n");
229 return NULL;
230 }
231
232 data->fd = fd;
233 data->dev_ops = dev_ops;
234 data->dev_ops_priv = dev_ops_priv;
235 data->decompress_pid = -1;
236 data->fps = 30;
237
238 /* Check supported formats */
239 for (i = 0; ; i++) {
240 struct v4l2_fmtdesc fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
241
242 fmt.index = i;
243
244 if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
245 VIDIOC_ENUM_FMT, &fmt))
246 break;
247
248 for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++)
249 if (fmt.pixelformat == supported_src_pixfmts[j].fmt)
250 break;
251
252 if (j < ARRAY_SIZE(supported_src_pixfmts)) {
253 set_bit(j, data->supported_src_formats);
254 v4lconvert_get_framesizes(data, fmt.pixelformat, j);
255 if (!supported_src_pixfmts[j].needs_conversion)
256 always_needs_conversion = 0;
257 } else
258 always_needs_conversion = 0;
259 }
260
261 data->no_formats = i;
262
263 /* Check if this cam has any special flags */
264 if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
265 VIDIOC_QUERYCAP, &cap) == 0) {
266 if (!strcmp((char *)cap.driver, "uvcvideo"))
267 data->flags |= V4LCONVERT_IS_UVC;
268
269 if (cap.capabilities & V4L2_CAP_DEVICE_CAPS)
270 cap.capabilities = cap.device_caps;
271 if ((cap.capabilities & 0xff) & ~V4L2_CAP_VIDEO_CAPTURE)
272 always_needs_conversion = 0;
273 }
274
275 data->control = v4lcontrol_create(fd, dev_ops_priv, dev_ops,
276 always_needs_conversion);
277 if (!data->control) {
278 free(data);
279 return NULL;
280 }
281 data->bandwidth = v4lcontrol_get_bandwidth(data->control);
282 data->control_flags = v4lcontrol_get_flags(data->control);
283 if (data->control_flags & V4LCONTROL_FORCE_TINYJPEG)
284 data->flags |= V4LCONVERT_USE_TINYJPEG;
285
286 data->processing = v4lprocessing_create(fd, data->control);
287 if (!data->processing) {
288 v4lcontrol_destroy(data->control);
289 free(data);
290 return NULL;
291 }
292
293 return data;
294 }
295
v4lconvert_destroy(struct v4lconvert_data * data)296 void v4lconvert_destroy(struct v4lconvert_data *data)
297 {
298 if (!data)
299 return;
300
301 v4lprocessing_destroy(data->processing);
302 v4lcontrol_destroy(data->control);
303 if (data->tinyjpeg) {
304 unsigned char *comps[3] = { NULL, NULL, NULL };
305
306 tinyjpeg_set_components(data->tinyjpeg, comps, 3);
307 tinyjpeg_free(data->tinyjpeg);
308 }
309 #ifdef HAVE_JPEG
310 if (data->cinfo_initialized)
311 jpeg_destroy_decompress(&data->cinfo);
312 #endif // HAVE_JPEG
313 #ifdef HAVE_LIBV4LCONVERT_HELPERS
314 v4lconvert_helper_cleanup(data);
315 #endif
316 free(data->convert1_buf);
317 free(data->convert2_buf);
318 free(data->rotate90_buf);
319 free(data->flip_buf);
320 free(data->convert_pixfmt_buf);
321 free(data->previous_frame);
322 free(data);
323 }
324
v4lconvert_supported_dst_format(unsigned int pixelformat)325 int v4lconvert_supported_dst_format(unsigned int pixelformat)
326 {
327 int i;
328
329 for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
330 if (supported_dst_pixfmts[i].fmt == pixelformat)
331 break;
332
333 return i != ARRAY_SIZE(supported_dst_pixfmts);
334 }
335
v4lconvert_supported_dst_fmt_only(struct v4lconvert_data * data)336 int v4lconvert_supported_dst_fmt_only(struct v4lconvert_data *data)
337 {
338 int i;
339
340 for (i = 0 ; i < ARRAY_SIZE(data->supported_src_formats); i++)
341 if (data->supported_src_formats[i])
342 break;
343 if (i == ARRAY_SIZE(data->supported_src_formats))
344 return 0;
345
346 return v4lcontrol_needs_conversion(data->control);
347 }
348
349 /* See libv4lconvert.h for description of in / out parameters */
v4lconvert_enum_fmt(struct v4lconvert_data * data,struct v4l2_fmtdesc * fmt)350 int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
351 {
352 int i, no_faked_fmts = 0;
353 unsigned int faked_fmts[ARRAY_SIZE(supported_dst_pixfmts)];
354
355 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
356 (!v4lconvert_supported_dst_fmt_only(data) &&
357 fmt->index < data->no_formats))
358 return data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
359 VIDIOC_ENUM_FMT, fmt);
360
361 for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
362 if (v4lconvert_supported_dst_fmt_only(data) ||
363 !test_bit(i, data->supported_src_formats)) {
364 faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i].fmt;
365 no_faked_fmts++;
366 }
367
368 if (!v4lconvert_supported_dst_fmt_only(data))
369 i = fmt->index - data->no_formats;
370 else
371 i = fmt->index;
372
373 if (i >= no_faked_fmts) {
374 errno = EINVAL;
375 return -1;
376 }
377
378 fmt->flags = V4L2_FMT_FLAG_EMULATED;
379 fmt->pixelformat = faked_fmts[i];
380 fmt->description[0] = faked_fmts[i] & 0xff;
381 fmt->description[1] = (faked_fmts[i] >> 8) & 0xff;
382 fmt->description[2] = (faked_fmts[i] >> 16) & 0xff;
383 fmt->description[3] = faked_fmts[i] >> 24;
384 fmt->description[4] = '\0';
385 memset(fmt->reserved, 0, sizeof(fmt->reserved));
386
387 return 0;
388 }
389
390 /* This function returns a value to rank (sort) source format by preference
391 when multiple source formats are available for a certain resolution, the
392 source format for which this function returns the lowest value wins.
393
394 This function uses the rgb_rank resp. yuv_rank values as a base when
395 converting to rgb32 resp. yuv420. The initial ranks range from 1 - 10,
396 the initial rank purely expresses the CPU cost of doing the conversion, the
397 ranking algorithm will give a penalty of 10 points if
398 (width * height * fps * bpp / 8) > bandwidth
399 thus disqualifying a src format which causes the bandwidth to be exceeded,
400 except when all of them cause this.
401
402 Note grey scale formats start at 20 rather than 1-10, because we want to
403 never autoselect them, unless they are the only choice */
v4lconvert_get_rank(struct v4lconvert_data * data,int src_index,int src_width,int src_height,unsigned int dest_pixelformat)404 static int v4lconvert_get_rank(struct v4lconvert_data *data,
405 int src_index, int src_width, int src_height,
406 unsigned int dest_pixelformat)
407 {
408 int needed, rank = 0;
409
410 switch (dest_pixelformat) {
411 case V4L2_PIX_FMT_RGB24:
412 case V4L2_PIX_FMT_BGR24:
413 rank = supported_src_pixfmts[src_index].rgb_rank;
414 break;
415 case V4L2_PIX_FMT_YUV420:
416 case V4L2_PIX_FMT_YVU420:
417 rank = supported_src_pixfmts[src_index].yuv_rank;
418 break;
419 }
420
421 /* So that if both rgb32 and bgr32 are supported, or both yuv420 and
422 yvu420 the right one wins */
423 if (supported_src_pixfmts[src_index].fmt == dest_pixelformat)
424 rank--;
425
426 /* check bandwidth needed */
427 needed = src_width * src_height * data->fps *
428 supported_src_pixfmts[src_index].bpp / 8;
429 if (data->bandwidth && needed > data->bandwidth)
430 rank += 10;
431 #if 0
432 printf("ranked: %c%c%c%c for %dx%d @ %d fps, needed: %d, bandwidth: %d, rank: %d\n",
433 supported_src_pixfmts[src_index].fmt & 0xff,
434 (supported_src_pixfmts[src_index].fmt >> 8) & 0xff,
435 (supported_src_pixfmts[src_index].fmt >> 16) & 0xff,
436 supported_src_pixfmts[src_index].fmt >> 24, src_width,
437 src_height, data->fps, needed, data->bandwidth, rank);
438 #endif
439 return rank;
440 }
441
442 /* Find out what format to use based on the (cached) results of enum
443 framesizes instead of doing a zillion try_fmt calls. This function
444 currently is intended for use with UVC cams only. This is esp.
445 important for UVC based cams as doing try_fmt there actually causes I/O */
v4lconvert_do_try_format_uvc(struct v4lconvert_data * data,struct v4l2_format * dest_fmt,struct v4l2_format * src_fmt)446 static int v4lconvert_do_try_format_uvc(struct v4lconvert_data *data,
447 struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
448 {
449 int i, rank;
450 unsigned int closest_fmt_size_diff = -1;
451 int best_framesize = 0;/* Just use the first format if no small enough one */
452 int best_format = 0;
453 int best_rank = 100;
454
455 for (i = 0; i < data->no_framesizes; i++) {
456 if (data->framesizes[i].discrete.width <= dest_fmt->fmt.pix.width &&
457 data->framesizes[i].discrete.height <= dest_fmt->fmt.pix.height) {
458 int size_x_diff = dest_fmt->fmt.pix.width -
459 data->framesizes[i].discrete.width;
460 int size_y_diff = dest_fmt->fmt.pix.height -
461 data->framesizes[i].discrete.height;
462 unsigned int size_diff = size_x_diff * size_x_diff +
463 size_y_diff * size_y_diff;
464
465 if (size_diff < closest_fmt_size_diff) {
466 closest_fmt_size_diff = size_diff;
467 best_framesize = i;
468 }
469 }
470 }
471
472 for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
473 /* is this format supported? */
474 if (!(data->framesize_supported_src_formats[best_framesize] &
475 (1ULL << i)))
476 continue;
477
478 /* Note the hardcoded use of discrete is based on this function
479 only getting called for uvc devices */
480 rank = v4lconvert_get_rank(data, i,
481 data->framesizes[best_framesize].discrete.width,
482 data->framesizes[best_framesize].discrete.height,
483 dest_fmt->fmt.pix.pixelformat);
484 if (rank < best_rank) {
485 best_rank = rank;
486 best_format = supported_src_pixfmts[i].fmt;
487 }
488 }
489
490 dest_fmt->fmt.pix.width = data->framesizes[best_framesize].discrete.width;
491 dest_fmt->fmt.pix.height = data->framesizes[best_framesize].discrete.height;
492 dest_fmt->fmt.pix.field = V4L2_FIELD_NONE; /* UVC has no fields */
493 /* Not pretty, the pwc driver doesn't fill these in try_fmt either though,
494 so we should be able to get away with this. */
495 dest_fmt->fmt.pix.bytesperline = 0;
496 dest_fmt->fmt.pix.sizeimage = 0;
497 dest_fmt->fmt.pix.colorspace = V4L2_COLORSPACE_DEFAULT;
498 dest_fmt->fmt.pix.priv = 0;
499
500 *src_fmt = *dest_fmt;
501 src_fmt->fmt.pix.pixelformat = best_format;
502
503 return 0;
504 }
505
v4lconvert_do_try_format(struct v4lconvert_data * data,struct v4l2_format * dest_fmt,struct v4l2_format * src_fmt)506 static int v4lconvert_do_try_format(struct v4lconvert_data *data,
507 struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
508 {
509 int i, size_x_diff, size_y_diff, rank, best_rank = 0;
510 unsigned int size_diff, closest_fmt_size_diff = -1;
511 unsigned int desired_pixfmt = dest_fmt->fmt.pix.pixelformat;
512 struct v4l2_format try_fmt, closest_fmt = { .type = 0 };
513
514 if (data->flags & V4LCONVERT_IS_UVC)
515 return v4lconvert_do_try_format_uvc(data, dest_fmt, src_fmt);
516
517 for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
518 /* is this format supported? */
519 if (!test_bit(i, data->supported_src_formats))
520 continue;
521
522 try_fmt = *dest_fmt;
523 try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt;
524 if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
525 VIDIOC_TRY_FMT, &try_fmt))
526 continue;
527
528 if (try_fmt.fmt.pix.pixelformat !=
529 supported_src_pixfmts[i].fmt)
530 continue;
531
532 /* Did we get a better match than before? */
533 size_x_diff = (int)try_fmt.fmt.pix.width -
534 (int)dest_fmt->fmt.pix.width;
535 size_y_diff = (int)try_fmt.fmt.pix.height -
536 (int)dest_fmt->fmt.pix.height;
537 size_diff = size_x_diff * size_x_diff +
538 size_y_diff * size_y_diff;
539
540 rank = v4lconvert_get_rank(data, i,
541 try_fmt.fmt.pix.width,
542 try_fmt.fmt.pix.height,
543 desired_pixfmt);
544 if (size_diff < closest_fmt_size_diff ||
545 (size_diff == closest_fmt_size_diff && rank < best_rank)) {
546 closest_fmt = try_fmt;
547 closest_fmt_size_diff = size_diff;
548 best_rank = rank;
549 }
550 }
551
552 if (closest_fmt.type == 0)
553 return -1;
554
555 *dest_fmt = closest_fmt;
556 if (closest_fmt.fmt.pix.pixelformat != desired_pixfmt)
557 dest_fmt->fmt.pix.pixelformat = desired_pixfmt;
558 *src_fmt = closest_fmt;
559
560 return 0;
561 }
562
v4lconvert_fixup_fmt(struct v4l2_format * fmt)563 void v4lconvert_fixup_fmt(struct v4l2_format *fmt)
564 {
565 switch (fmt->fmt.pix.pixelformat) {
566 case V4L2_PIX_FMT_RGB24:
567 case V4L2_PIX_FMT_BGR24:
568 fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * 3;
569 fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3;
570 break;
571 case V4L2_PIX_FMT_YUV420:
572 case V4L2_PIX_FMT_YVU420:
573 fmt->fmt.pix.bytesperline = fmt->fmt.pix.width;
574 fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3 / 2;
575 break;
576 }
577 }
578
579 /* See libv4lconvert.h for description of in / out parameters */
v4lconvert_try_format(struct v4lconvert_data * data,struct v4l2_format * dest_fmt,struct v4l2_format * src_fmt)580 int v4lconvert_try_format(struct v4lconvert_data *data,
581 struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
582 {
583 int i, result;
584 unsigned int desired_width = dest_fmt->fmt.pix.width;
585 unsigned int desired_height = dest_fmt->fmt.pix.height;
586 struct v4l2_format try_src, try_dest, try2_src, try2_dest;
587
588 if (dest_fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
589 v4lconvert_supported_dst_fmt_only(data) &&
590 !v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat))
591 dest_fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
592
593 try_dest = *dest_fmt;
594
595 /* Can we do conversion to the requested format & type? */
596 if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) ||
597 dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
598 v4lconvert_do_try_format(data, &try_dest, &try_src)) {
599 result = data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
600 VIDIOC_TRY_FMT, dest_fmt);
601 if (src_fmt)
602 *src_fmt = *dest_fmt;
603 return result;
604 }
605
606 /* In case of a non exact resolution match, try again with a slightly larger
607 resolution as some weird devices are not able to crop of the number of
608 extra (border) pixels most sensors have compared to standard resolutions,
609 which we will then just crop off in software */
610 if (try_dest.fmt.pix.width != desired_width ||
611 try_dest.fmt.pix.height != desired_height) {
612 try2_dest = *dest_fmt;
613 try2_dest.fmt.pix.width = desired_width + 7;
614 try2_dest.fmt.pix.height = desired_height + 1;
615 result = v4lconvert_do_try_format(data, &try2_dest, &try2_src);
616 if (result == 0 &&
617 try2_dest.fmt.pix.width >= desired_width &&
618 try2_dest.fmt.pix.width <= desired_width + 7 &&
619 try2_dest.fmt.pix.height >= desired_height &&
620 try2_dest.fmt.pix.height <= desired_height + 1) {
621 /* Success! */
622 try2_dest.fmt.pix.width = desired_width;
623 try2_dest.fmt.pix.height = desired_height;
624 try_dest = try2_dest;
625 try_src = try2_src;
626 }
627 }
628
629 /* In case of a non exact resolution match, see if this is a well known
630 resolution some apps are hardcoded too and try to give the app what it
631 asked for by cropping a slightly larger resolution or adding a small
632 black border to a slightly smaller resolution */
633 if (try_dest.fmt.pix.width != desired_width ||
634 try_dest.fmt.pix.height != desired_height) {
635 for (i = 0; i < ARRAY_SIZE(v4lconvert_crop_res); i++) {
636 if (v4lconvert_crop_res[i][0] == desired_width &&
637 v4lconvert_crop_res[i][1] == desired_height) {
638 try2_dest = *dest_fmt;
639
640 /* Note these are chosen so that cropping to vga res just works for
641 vv6410 sensor cams, which have 356x292 and 180x148 */
642 try2_dest.fmt.pix.width = desired_width * 113 / 100;
643 try2_dest.fmt.pix.height = desired_height * 124 / 100;
644 result = v4lconvert_do_try_format(data, &try2_dest, &try2_src);
645 if (result == 0 &&
646 (/* Add a small black border of max 16 pixels */
647 (try2_dest.fmt.pix.width >= desired_width - 16 &&
648 try2_dest.fmt.pix.width <= desired_width &&
649 try2_dest.fmt.pix.height >= desired_height - 16 &&
650 try2_dest.fmt.pix.height <= desired_height) ||
651 /* Standard cropping to max 80% of actual width / height */
652 (try2_dest.fmt.pix.width >= desired_width &&
653 try2_dest.fmt.pix.width <= desired_width * 5 / 4 &&
654 try2_dest.fmt.pix.height >= desired_height &&
655 try2_dest.fmt.pix.height <= desired_height * 5 / 4) ||
656 /* Downscale 2x + cropping to max 80% of actual width / height */
657 (try2_dest.fmt.pix.width >= desired_width * 2 &&
658 try2_dest.fmt.pix.width <= desired_width * 5 / 2 &&
659 try2_dest.fmt.pix.height >= desired_height * 2 &&
660 try2_dest.fmt.pix.height <= desired_height * 5 / 2))) {
661 /* Success! */
662 try2_dest.fmt.pix.width = desired_width;
663 try2_dest.fmt.pix.height = desired_height;
664 try_dest = try2_dest;
665 try_src = try2_src;
666 }
667 break;
668 }
669 }
670 }
671
672 /* Some applications / libs (*cough* gstreamer *cough*) will not work
673 correctly with planar YUV formats when the width is not a multiple of 8
674 or the height is not a multiple of 2. With RGB formats these apps require
675 the width to be a multiple of 4. We apply the same rounding to all
676 formats to not end up with 2 close but different resolutions. */
677 try_dest.fmt.pix.width &= ~7;
678 try_dest.fmt.pix.height &= ~1;
679
680 /* Are we converting / cropping ? */
681 if (try_src.fmt.pix.width != try_dest.fmt.pix.width ||
682 try_src.fmt.pix.height != try_dest.fmt.pix.height ||
683 try_src.fmt.pix.pixelformat != try_dest.fmt.pix.pixelformat)
684 v4lconvert_fixup_fmt(&try_dest);
685
686 *dest_fmt = try_dest;
687 if (src_fmt)
688 *src_fmt = try_src;
689
690 return 0;
691 }
692
693 /* Is conversion necessary ? */
v4lconvert_needs_conversion(struct v4lconvert_data * data,const struct v4l2_format * src_fmt,const struct v4l2_format * dest_fmt)694 int v4lconvert_needs_conversion(struct v4lconvert_data *data,
695 const struct v4l2_format *src_fmt, /* in */
696 const struct v4l2_format *dest_fmt) /* in */
697 {
698 if (src_fmt->fmt.pix.width != dest_fmt->fmt.pix.width ||
699 src_fmt->fmt.pix.height != dest_fmt->fmt.pix.height ||
700 src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat ||
701 (v4lcontrol_needs_conversion(data->control) &&
702 v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)))
703 return 1;
704
705 return 0;
706 }
707
v4lconvert_processing_needs_double_conversion(unsigned int src_pix_fmt,unsigned int dest_pix_fmt)708 static int v4lconvert_processing_needs_double_conversion(
709 unsigned int src_pix_fmt, unsigned int dest_pix_fmt)
710 {
711 switch (src_pix_fmt) {
712 case V4L2_PIX_FMT_RGB24:
713 case V4L2_PIX_FMT_BGR24:
714 case V4L2_PIX_FMT_SPCA561:
715 case V4L2_PIX_FMT_SN9C10X:
716 case V4L2_PIX_FMT_PAC207:
717 case V4L2_PIX_FMT_MR97310A:
718 #ifdef HAVE_JPEG
719 case V4L2_PIX_FMT_JL2005BCD:
720 #endif
721 case V4L2_PIX_FMT_SN9C2028:
722 case V4L2_PIX_FMT_SQ905C:
723 case V4L2_PIX_FMT_SBGGR8:
724 case V4L2_PIX_FMT_SGBRG8:
725 case V4L2_PIX_FMT_SGRBG8:
726 case V4L2_PIX_FMT_SRGGB8:
727 case V4L2_PIX_FMT_SBGGR10P:
728 case V4L2_PIX_FMT_SGBRG10P:
729 case V4L2_PIX_FMT_SGRBG10P:
730 case V4L2_PIX_FMT_SRGGB10P:
731 case V4L2_PIX_FMT_SBGGR10:
732 case V4L2_PIX_FMT_SGBRG10:
733 case V4L2_PIX_FMT_SGRBG10:
734 case V4L2_PIX_FMT_SRGGB10:
735 case V4L2_PIX_FMT_SBGGR16:
736 case V4L2_PIX_FMT_SGBRG16:
737 case V4L2_PIX_FMT_SGRBG16:
738 case V4L2_PIX_FMT_SRGGB16:
739 case V4L2_PIX_FMT_STV0680:
740 return 0;
741 }
742 switch (dest_pix_fmt) {
743 case V4L2_PIX_FMT_RGB24:
744 case V4L2_PIX_FMT_BGR24:
745 return 0;
746 }
747
748 return 1;
749 }
750
v4lconvert_alloc_buffer(int needed,unsigned char ** buf,int * buf_size)751 unsigned char *v4lconvert_alloc_buffer(int needed,
752 unsigned char **buf, int *buf_size)
753 {
754 if (*buf_size < needed) {
755 free(*buf);
756 *buf = malloc(needed);
757 if (*buf == NULL) {
758 *buf_size = 0;
759 return NULL;
760 }
761 *buf_size = needed;
762 }
763 return *buf;
764 }
765
v4lconvert_oom_error(struct v4lconvert_data * data)766 int v4lconvert_oom_error(struct v4lconvert_data *data)
767 {
768 V4LCONVERT_ERR("could not allocate memory\n");
769 errno = ENOMEM;
770 return -1;
771 }
772
v4lconvert_convert_pixfmt(struct v4lconvert_data * data,unsigned char * src,int src_size,unsigned char * dest,int dest_size,struct v4l2_format * fmt,unsigned int dest_pix_fmt)773 static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
774 unsigned char *src, int src_size, unsigned char *dest, int dest_size,
775 struct v4l2_format *fmt, unsigned int dest_pix_fmt)
776 {
777 int result = 0;
778 unsigned int src_pix_fmt = fmt->fmt.pix.pixelformat;
779 unsigned int width = fmt->fmt.pix.width;
780 unsigned int height = fmt->fmt.pix.height;
781 unsigned int bytesperline = fmt->fmt.pix.bytesperline;
782
783 switch (src_pix_fmt) {
784 /* JPG and variants */
785 case V4L2_PIX_FMT_MJPEG:
786 case V4L2_PIX_FMT_JPEG:
787 #ifdef HAVE_JPEG
788 if (data->flags & V4LCONVERT_USE_TINYJPEG) {
789 #endif // HAVE_JPEG
790 result = v4lconvert_decode_jpeg_tinyjpeg(data,
791 src, src_size, dest,
792 fmt, dest_pix_fmt, 0);
793 #ifdef HAVE_JPEG
794 } else {
795 result = v4lconvert_decode_jpeg_libjpeg(data,
796 src, src_size, dest,
797 fmt, dest_pix_fmt);
798 if (result == -1 && errno == EOPNOTSUPP) {
799 /* Fall back to tinyjpeg */
800 jpeg_destroy_decompress(&data->cinfo);
801 data->cinfo_initialized = 0;
802 data->flags |= V4LCONVERT_USE_TINYJPEG;
803 result = v4lconvert_decode_jpeg_tinyjpeg(data,
804 src, src_size, dest,
805 fmt, dest_pix_fmt, 0);
806 }
807 }
808 #endif // HAVE_JPEG
809 break;
810 case V4L2_PIX_FMT_PJPG:
811 result = v4lconvert_decode_jpeg_tinyjpeg(data, src, src_size,
812 dest, fmt, dest_pix_fmt,
813 TINYJPEG_FLAGS_PIXART_JPEG);
814 break;
815 case V4L2_PIX_FMT_JPGL:
816 result = v4lconvert_decode_jpgl(src, src_size, dest_pix_fmt,
817 dest, width, height);
818 break;
819
820 /* Custom cam specific YUV formats */
821 case V4L2_PIX_FMT_SPCA501:
822 case V4L2_PIX_FMT_SPCA505:
823 case V4L2_PIX_FMT_SPCA508:
824 case V4L2_PIX_FMT_CIT_YYVYUY:
825 case V4L2_PIX_FMT_KONICA420:
826 case V4L2_PIX_FMT_M420:
827 case V4L2_PIX_FMT_SN9C20X_I420:
828 case V4L2_PIX_FMT_CPIA1:
829 case V4L2_PIX_FMT_OV511:
830 case V4L2_PIX_FMT_OV518: {
831 unsigned char *d;
832 int d_size;
833 int yvu = 0;
834
835 if (dest_pix_fmt != V4L2_PIX_FMT_YUV420 &&
836 dest_pix_fmt != V4L2_PIX_FMT_YVU420) {
837 d = v4lconvert_alloc_buffer(width * height * 3 / 2,
838 &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
839 if (!d)
840 return v4lconvert_oom_error(data);
841 d_size = width * height * 3 / 2;
842 } else {
843 d = dest;
844 d_size = dest_size;
845 }
846
847 if (dest_pix_fmt == V4L2_PIX_FMT_YVU420)
848 yvu = 1;
849
850 switch (src_pix_fmt) {
851 case V4L2_PIX_FMT_SPCA501:
852 v4lconvert_spca501_to_yuv420(src, d, width, height, yvu);
853 break;
854 case V4L2_PIX_FMT_SPCA505:
855 v4lconvert_spca505_to_yuv420(src, d, width, height, yvu);
856 break;
857 case V4L2_PIX_FMT_SPCA508:
858 v4lconvert_spca508_to_yuv420(src, d, width, height, yvu);
859 break;
860 case V4L2_PIX_FMT_CIT_YYVYUY:
861 v4lconvert_cit_yyvyuy_to_yuv420(src, d, width, height, yvu);
862 break;
863 case V4L2_PIX_FMT_KONICA420:
864 v4lconvert_konica_yuv420_to_yuv420(src, d, width, height, yvu);
865 break;
866 case V4L2_PIX_FMT_M420:
867 v4lconvert_m420_to_yuv420(src, d, width, height, yvu);
868 break;
869 case V4L2_PIX_FMT_SN9C20X_I420:
870 v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu);
871 break;
872 case V4L2_PIX_FMT_CPIA1:
873 if (v4lconvert_cpia1_to_yuv420(data, src, src_size, d,
874 width, height, yvu)) {
875 /* Corrupt frame, better get another one */
876 errno = EAGAIN;
877 return -1;
878 }
879 break;
880 #ifdef HAVE_LIBV4LCONVERT_HELPERS
881 case V4L2_PIX_FMT_OV511:
882 if (v4lconvert_helper_decompress(data, LIBV4LCONVERT_PRIV_DIR "/ov511-decomp",
883 src, src_size, d, d_size, width, height, yvu)) {
884 /* Corrupt frame, better get another one */
885 errno = EAGAIN;
886 return -1;
887 }
888 break;
889 case V4L2_PIX_FMT_OV518:
890 if (v4lconvert_helper_decompress(data, LIBV4LCONVERT_PRIV_DIR "/ov518-decomp",
891 src, src_size, d, d_size, width, height, yvu)) {
892 /* Corrupt frame, better get another one */
893 errno = EAGAIN;
894 return -1;
895 }
896 break;
897 #endif
898 }
899
900 switch (dest_pix_fmt) {
901 case V4L2_PIX_FMT_RGB24:
902 v4lconvert_yuv420_to_rgb24(data->convert_pixfmt_buf, dest, width,
903 height, bytesperline, yvu);
904 break;
905 case V4L2_PIX_FMT_BGR24:
906 v4lconvert_yuv420_to_bgr24(data->convert_pixfmt_buf, dest, width,
907 height, bytesperline, yvu);
908 break;
909 }
910 break;
911 }
912
913 /* Conexant cx2341x raw video macroblock format */
914 case V4L2_PIX_FMT_NV12_16L16:
915 switch (dest_pix_fmt) {
916 case V4L2_PIX_FMT_RGB24:
917 v4lconvert_nv12_16l16_to_rgb24(src, dest, width, height);
918 break;
919 case V4L2_PIX_FMT_BGR24:
920 v4lconvert_nv12_16l16_to_bgr24(src, dest, width, height);
921 break;
922 case V4L2_PIX_FMT_YUV420:
923 v4lconvert_nv12_16l16_to_yuv420(src, dest, width, height, 0);
924 break;
925 case V4L2_PIX_FMT_YVU420:
926 v4lconvert_nv12_16l16_to_yuv420(src, dest, width, height, 1);
927 break;
928 }
929 break;
930
931 /* NV12 formats */
932 case V4L2_PIX_FMT_NV12:
933 switch (dest_pix_fmt) {
934 case V4L2_PIX_FMT_RGB24:
935 v4lconvert_nv12_to_rgb24(src, dest, width, height, bytesperline, 0);
936 break;
937 case V4L2_PIX_FMT_BGR24:
938 v4lconvert_nv12_to_rgb24(src, dest, width, height, bytesperline, 1);
939 break;
940 case V4L2_PIX_FMT_YUV420:
941 v4lconvert_nv12_to_yuv420(src, dest, width, height, bytesperline, 0);
942 break;
943 case V4L2_PIX_FMT_YVU420:
944 v4lconvert_nv12_to_yuv420(src, dest, width, height, bytesperline, 1);
945 break;
946 }
947 break;
948
949 /* compressed bayer formats */
950 case V4L2_PIX_FMT_SPCA561:
951 case V4L2_PIX_FMT_SN9C10X:
952 case V4L2_PIX_FMT_PAC207:
953 case V4L2_PIX_FMT_MR97310A:
954 #ifdef HAVE_JPEG
955 case V4L2_PIX_FMT_JL2005BCD:
956 #endif
957 case V4L2_PIX_FMT_SN9C2028:
958 case V4L2_PIX_FMT_SQ905C:
959 case V4L2_PIX_FMT_STV0680: { /* Not compressed but needs some shuffling */
960 unsigned char *tmpbuf;
961 struct v4l2_format tmpfmt = *fmt;
962
963 tmpbuf = v4lconvert_alloc_buffer(width * height,
964 &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
965 if (!tmpbuf)
966 return v4lconvert_oom_error(data);
967
968 switch (src_pix_fmt) {
969 case V4L2_PIX_FMT_SPCA561:
970 v4lconvert_decode_spca561(src, tmpbuf, width, height);
971 tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGBRG8;
972 break;
973 case V4L2_PIX_FMT_SN9C10X:
974 v4lconvert_decode_sn9c10x(src, tmpbuf, width, height);
975 tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
976 break;
977 case V4L2_PIX_FMT_PAC207:
978 if (v4lconvert_decode_pac207(data, src, src_size, tmpbuf,
979 width, height)) {
980 /* Corrupt frame, better get another one */
981 errno = EAGAIN;
982 return -1;
983 }
984 tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
985 break;
986 case V4L2_PIX_FMT_MR97310A:
987 if (v4lconvert_decode_mr97310a(data, src, src_size, tmpbuf,
988 width, height)) {
989 /* Corrupt frame, better get another one */
990 errno = EAGAIN;
991 return -1;
992 }
993 tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
994 break;
995 #ifdef HAVE_JPEG
996 case V4L2_PIX_FMT_JL2005BCD:
997 if (v4lconvert_decode_jl2005bcd(data, src, src_size,
998 tmpbuf,
999 width, height)) {
1000 /* Corrupt frame, better get another one */
1001 errno = EAGAIN;
1002 return -1;
1003 }
1004 tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
1005 break;
1006 #endif
1007 case V4L2_PIX_FMT_SN9C2028:
1008 v4lconvert_decode_sn9c2028(src, tmpbuf, width, height);
1009 tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
1010 break;
1011 case V4L2_PIX_FMT_SQ905C:
1012 v4lconvert_decode_sq905c(src, tmpbuf, width, height);
1013 tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
1014 break;
1015 case V4L2_PIX_FMT_STV0680:
1016 v4lconvert_decode_stv0680(src, tmpbuf, width, height);
1017 tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
1018 break;
1019 }
1020 /* Do processing on the tmp buffer, because doing it on bayer data is
1021 cheaper, and bayer == rgb and our dest_fmt may be yuv */
1022 tmpfmt.fmt.pix.bytesperline = width;
1023 tmpfmt.fmt.pix.sizeimage = width * height;
1024 v4lprocessing_processing(data->processing, tmpbuf, &tmpfmt);
1025 /* Deliberate fall through to raw bayer fmt code! */
1026 src_pix_fmt = tmpfmt.fmt.pix.pixelformat;
1027 src = tmpbuf;
1028 src_size = width * height;
1029 /* fall through */
1030 }
1031
1032 /* Raw bayer formats */
1033 case V4L2_PIX_FMT_SBGGR10P:
1034 case V4L2_PIX_FMT_SGBRG10P:
1035 case V4L2_PIX_FMT_SGRBG10P:
1036 case V4L2_PIX_FMT_SRGGB10P: {
1037 int b10format = 1;
1038
1039 switch (src_pix_fmt) {
1040 case V4L2_PIX_FMT_SBGGR10P:
1041 src_pix_fmt = V4L2_PIX_FMT_SBGGR8;
1042 break;
1043 case V4L2_PIX_FMT_SGBRG10P:
1044 src_pix_fmt = V4L2_PIX_FMT_SGBRG8;
1045 break;
1046 case V4L2_PIX_FMT_SGRBG10P:
1047 src_pix_fmt = V4L2_PIX_FMT_SGRBG8;
1048 break;
1049 case V4L2_PIX_FMT_SRGGB10P:
1050 src_pix_fmt = V4L2_PIX_FMT_SRGGB8;
1051 break;
1052 default:
1053 b10format = 0;
1054 break;
1055 }
1056
1057 if (b10format) {
1058 if (src_size < ((width * height * 10)/8)) {
1059 V4LCONVERT_ERR
1060 ("short raw bayer10 data frame\n");
1061 errno = EPIPE;
1062 result = -1;
1063 break;
1064 }
1065 v4lconvert_bayer10p_to_bayer8(src, src, width, height);
1066 bytesperline = width;
1067 }
1068 }
1069
1070 case V4L2_PIX_FMT_SBGGR10:
1071 case V4L2_PIX_FMT_SGBRG10:
1072 case V4L2_PIX_FMT_SGRBG10:
1073 case V4L2_PIX_FMT_SRGGB10: {
1074 int b10format = 1;
1075
1076 switch (src_pix_fmt) {
1077 case V4L2_PIX_FMT_SBGGR10:
1078 src_pix_fmt = V4L2_PIX_FMT_SBGGR8;
1079 break;
1080 case V4L2_PIX_FMT_SGBRG10:
1081 src_pix_fmt = V4L2_PIX_FMT_SGBRG8;
1082 break;
1083 case V4L2_PIX_FMT_SGRBG10:
1084 src_pix_fmt = V4L2_PIX_FMT_SGRBG8;
1085 break;
1086 case V4L2_PIX_FMT_SRGGB10:
1087 src_pix_fmt = V4L2_PIX_FMT_SRGGB8;
1088 break;
1089 default:
1090 b10format = 0;
1091 break;
1092 }
1093
1094 if (b10format) {
1095 if (src_size < (width * height * 2)) {
1096 V4LCONVERT_ERR
1097 ("short raw bayer10 data frame\n");
1098 errno = EPIPE;
1099 result = -1;
1100 break;
1101 }
1102 v4lconvert_bayer10_to_bayer8(src, src, width, height);
1103 bytesperline = width;
1104 }
1105 }
1106
1107 case V4L2_PIX_FMT_SBGGR16:
1108 case V4L2_PIX_FMT_SGBRG16:
1109 case V4L2_PIX_FMT_SGRBG16:
1110 case V4L2_PIX_FMT_SRGGB16: {
1111 int b16format = 1;
1112
1113 switch (src_pix_fmt) {
1114 case V4L2_PIX_FMT_SBGGR16:
1115 src_pix_fmt = V4L2_PIX_FMT_SBGGR8;
1116 break;
1117 case V4L2_PIX_FMT_SGBRG16:
1118 src_pix_fmt = V4L2_PIX_FMT_SGBRG8;
1119 break;
1120 case V4L2_PIX_FMT_SGRBG16:
1121 src_pix_fmt = V4L2_PIX_FMT_SGRBG8;
1122 break;
1123 case V4L2_PIX_FMT_SRGGB16:
1124 src_pix_fmt = V4L2_PIX_FMT_SRGGB8;
1125 break;
1126 default:
1127 b16format = 0;
1128 break;
1129 }
1130
1131 if (b16format) {
1132 if (src_size < ((width * height * 2))) {
1133 V4LCONVERT_ERR
1134 ("short raw bayer16 data frame\n");
1135 errno = EPIPE;
1136 result = -1;
1137 break;
1138 }
1139 v4lconvert_bayer16_to_bayer8(src, src, width, height);
1140 bytesperline = width;
1141 }
1142 }
1143
1144 /* Fall-through*/
1145 case V4L2_PIX_FMT_SBGGR8:
1146 case V4L2_PIX_FMT_SGBRG8:
1147 case V4L2_PIX_FMT_SGRBG8:
1148 case V4L2_PIX_FMT_SRGGB8:
1149 if (src_size < (width * height)) {
1150 V4LCONVERT_ERR("short raw bayer data frame\n");
1151 errno = EPIPE;
1152 result = -1;
1153 }
1154 switch (dest_pix_fmt) {
1155 case V4L2_PIX_FMT_RGB24:
1156 v4lconvert_bayer_to_rgb24(src, dest, width, height, bytesperline, src_pix_fmt);
1157 break;
1158 case V4L2_PIX_FMT_BGR24:
1159 v4lconvert_bayer_to_bgr24(src, dest, width, height, bytesperline, src_pix_fmt);
1160 break;
1161 case V4L2_PIX_FMT_YUV420:
1162 v4lconvert_bayer_to_yuv420(src, dest, width, height, bytesperline, src_pix_fmt, 0);
1163 break;
1164 case V4L2_PIX_FMT_YVU420:
1165 v4lconvert_bayer_to_yuv420(src, dest, width, height, bytesperline, src_pix_fmt, 1);
1166 break;
1167 }
1168 break;
1169
1170 case V4L2_PIX_FMT_SE401: {
1171 unsigned char *d = NULL;
1172
1173 switch (dest_pix_fmt) {
1174 case V4L2_PIX_FMT_RGB24:
1175 d = dest;
1176 break;
1177 case V4L2_PIX_FMT_BGR24:
1178 case V4L2_PIX_FMT_YUV420:
1179 case V4L2_PIX_FMT_YVU420:
1180 d = v4lconvert_alloc_buffer(width * height * 3,
1181 &data->convert_pixfmt_buf,
1182 &data->convert_pixfmt_buf_size);
1183 if (!d)
1184 return v4lconvert_oom_error(data);
1185
1186 fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
1187 v4lconvert_fixup_fmt(fmt);
1188 break;
1189 default:
1190 V4LCONVERT_ERR("Unknown destination format in conversion\n");
1191 errno = EINVAL;
1192 return -1;
1193 }
1194
1195 result = v4lconvert_se401_to_rgb24(data, src, src_size, d,
1196 width, height);
1197 switch (dest_pix_fmt) {
1198 case V4L2_PIX_FMT_BGR24:
1199 v4lconvert_swap_rgb(d, dest, width, height);
1200 break;
1201 case V4L2_PIX_FMT_YUV420:
1202 v4lconvert_rgb24_to_yuv420(d, dest, fmt, 0, 0, 3);
1203 break;
1204 case V4L2_PIX_FMT_YVU420:
1205 v4lconvert_rgb24_to_yuv420(d, dest, fmt, 0, 1, 3);
1206 break;
1207 }
1208 break;
1209 }
1210
1211 case V4L2_PIX_FMT_Y16:
1212 case V4L2_PIX_FMT_Y16_BE:
1213 if (src_size < (width * height * 2)) {
1214 V4LCONVERT_ERR("short y16 data frame\n");
1215 errno = EPIPE;
1216 result = -1;
1217 }
1218 switch (dest_pix_fmt) {
1219 case V4L2_PIX_FMT_RGB24:
1220 case V4L2_PIX_FMT_BGR24:
1221 v4lconvert_y16_to_rgb24(src, dest, width, height,
1222 src_pix_fmt == V4L2_PIX_FMT_Y16);
1223 break;
1224 case V4L2_PIX_FMT_YUV420:
1225 case V4L2_PIX_FMT_YVU420:
1226 v4lconvert_y16_to_yuv420(src, dest, fmt,
1227 src_pix_fmt == V4L2_PIX_FMT_Y16);
1228 break;
1229 }
1230 break;
1231
1232 case V4L2_PIX_FMT_GREY:
1233 case V4L2_PIX_FMT_Y4:
1234 case V4L2_PIX_FMT_Y6:
1235 if (src_size < (width * height)) {
1236 V4LCONVERT_ERR("short grey data frame\n");
1237 errno = EPIPE;
1238 result = -1;
1239 }
1240 switch (dest_pix_fmt) {
1241 case V4L2_PIX_FMT_RGB24:
1242 case V4L2_PIX_FMT_BGR24:
1243 v4lconvert_grey_to_rgb24(src, dest, width, height, bytesperline);
1244 break;
1245 case V4L2_PIX_FMT_YUV420:
1246 case V4L2_PIX_FMT_YVU420:
1247 v4lconvert_grey_to_yuv420(src, dest, fmt);
1248 break;
1249 }
1250 break;
1251
1252 case V4L2_PIX_FMT_Y10BPACK:
1253 if (src_size < (width * height * 10 / 8)) {
1254 V4LCONVERT_ERR("short y10b data frame\n");
1255 errno = EPIPE;
1256 result = -1;
1257 }
1258 switch (dest_pix_fmt) {
1259 case V4L2_PIX_FMT_RGB24:
1260 case V4L2_PIX_FMT_BGR24:
1261 result = v4lconvert_y10b_to_rgb24(data, src, dest,
1262 width, height);
1263 break;
1264 case V4L2_PIX_FMT_YUV420:
1265 case V4L2_PIX_FMT_YVU420:
1266 result = v4lconvert_y10b_to_yuv420(data, src, dest,
1267 width, height);
1268 break;
1269 }
1270 break;
1271
1272 case V4L2_PIX_FMT_RGB565:
1273 if (src_size < (width * height * 2)) {
1274 V4LCONVERT_ERR("short rgb565 data frame\n");
1275 errno = EPIPE;
1276 result = -1;
1277 }
1278 switch (dest_pix_fmt) {
1279 case V4L2_PIX_FMT_RGB24:
1280 v4lconvert_rgb565_to_rgb24(src, dest, width, height, bytesperline);
1281 break;
1282 case V4L2_PIX_FMT_BGR24:
1283 v4lconvert_rgb565_to_bgr24(src, dest, width, height, bytesperline);
1284 break;
1285 case V4L2_PIX_FMT_YUV420:
1286 v4lconvert_rgb565_to_yuv420(src, dest, fmt, 0);
1287 break;
1288 case V4L2_PIX_FMT_YVU420:
1289 v4lconvert_rgb565_to_yuv420(src, dest, fmt, 1);
1290 break;
1291 }
1292 break;
1293
1294 case V4L2_PIX_FMT_RGB24:
1295 if (src_size < (width * height * 3)) {
1296 V4LCONVERT_ERR("short rgb24 data frame\n");
1297 errno = EPIPE;
1298 result = -1;
1299 }
1300 switch (dest_pix_fmt) {
1301 case V4L2_PIX_FMT_RGB24:
1302 memcpy(dest, src, width * height * 3);
1303 break;
1304 case V4L2_PIX_FMT_BGR24:
1305 v4lconvert_swap_rgb(src, dest, width, height);
1306 break;
1307 case V4L2_PIX_FMT_YUV420:
1308 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 0, 3);
1309 break;
1310 case V4L2_PIX_FMT_YVU420:
1311 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 1, 3);
1312 break;
1313 }
1314 break;
1315
1316 case V4L2_PIX_FMT_BGR24:
1317 if (src_size < (width * height * 3)) {
1318 V4LCONVERT_ERR("short bgr24 data frame\n");
1319 errno = EPIPE;
1320 result = -1;
1321 }
1322 switch (dest_pix_fmt) {
1323 case V4L2_PIX_FMT_RGB24:
1324 v4lconvert_swap_rgb(src, dest, width, height);
1325 break;
1326 case V4L2_PIX_FMT_BGR24:
1327 memcpy(dest, src, width * height * 3);
1328 break;
1329 case V4L2_PIX_FMT_YUV420:
1330 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 0, 3);
1331 break;
1332 case V4L2_PIX_FMT_YVU420:
1333 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 1, 3);
1334 break;
1335 }
1336 break;
1337
1338 case V4L2_PIX_FMT_RGB32:
1339 case V4L2_PIX_FMT_XRGB32:
1340 case V4L2_PIX_FMT_ARGB32:
1341 if (src_size < (width * height * 4)) {
1342 V4LCONVERT_ERR("short rgb32 data frame\n");
1343 errno = EPIPE;
1344 result = -1;
1345 }
1346 src++;
1347 switch (dest_pix_fmt) {
1348 case V4L2_PIX_FMT_RGB24:
1349 v4lconvert_rgb32_to_rgb24(src, dest, width, height, 0);
1350 break;
1351 case V4L2_PIX_FMT_BGR24:
1352 v4lconvert_rgb32_to_rgb24(src, dest, width, height, 1);
1353 break;
1354 case V4L2_PIX_FMT_YUV420:
1355 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 0, 4);
1356 break;
1357 case V4L2_PIX_FMT_YVU420:
1358 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 1, 4);
1359 break;
1360 }
1361 break;
1362
1363 case V4L2_PIX_FMT_BGR32:
1364 case V4L2_PIX_FMT_XBGR32:
1365 case V4L2_PIX_FMT_ABGR32:
1366 if (src_size < (width * height * 4)) {
1367 V4LCONVERT_ERR("short bgr32 data frame\n");
1368 errno = EPIPE;
1369 result = -1;
1370 }
1371 switch (dest_pix_fmt) {
1372 case V4L2_PIX_FMT_RGB24:
1373 v4lconvert_rgb32_to_rgb24(src, dest, width, height, 1);
1374 break;
1375 case V4L2_PIX_FMT_BGR24:
1376 v4lconvert_rgb32_to_rgb24(src, dest, width, height, 0);
1377 break;
1378 case V4L2_PIX_FMT_YUV420:
1379 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 0, 4);
1380 break;
1381 case V4L2_PIX_FMT_YVU420:
1382 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 1, 4);
1383 break;
1384 }
1385 break;
1386
1387 case V4L2_PIX_FMT_YUV420:
1388 if (src_size < (width * height * 3 / 2)) {
1389 V4LCONVERT_ERR("short yuv420 data frame\n");
1390 errno = EPIPE;
1391 result = -1;
1392 }
1393 switch (dest_pix_fmt) {
1394 case V4L2_PIX_FMT_RGB24:
1395 v4lconvert_yuv420_to_rgb24(src, dest, width,
1396 height, bytesperline, 0);
1397 break;
1398 case V4L2_PIX_FMT_BGR24:
1399 v4lconvert_yuv420_to_bgr24(src, dest, width,
1400 height, bytesperline, 0);
1401 break;
1402 case V4L2_PIX_FMT_YUV420:
1403 memcpy(dest, src, width * height * 3 / 2);
1404 break;
1405 case V4L2_PIX_FMT_YVU420:
1406 v4lconvert_swap_uv(src, dest, fmt);
1407 break;
1408 }
1409 break;
1410
1411 case V4L2_PIX_FMT_YVU420:
1412 if (src_size < (width * height * 3 / 2)) {
1413 V4LCONVERT_ERR("short yvu420 data frame\n");
1414 errno = EPIPE;
1415 result = -1;
1416 }
1417 switch (dest_pix_fmt) {
1418 case V4L2_PIX_FMT_RGB24:
1419 v4lconvert_yuv420_to_rgb24(src, dest, width,
1420 height, bytesperline, 1);
1421 break;
1422 case V4L2_PIX_FMT_BGR24:
1423 v4lconvert_yuv420_to_bgr24(src, dest, width,
1424 height, bytesperline, 1);
1425 break;
1426 case V4L2_PIX_FMT_YUV420:
1427 v4lconvert_swap_uv(src, dest, fmt);
1428 break;
1429 case V4L2_PIX_FMT_YVU420:
1430 memcpy(dest, src, width * height * 3 / 2);
1431 break;
1432 }
1433 break;
1434
1435 case V4L2_PIX_FMT_NV16: {
1436 unsigned char *tmpbuf;
1437
1438 tmpbuf = v4lconvert_alloc_buffer(width * height * 2,
1439 &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
1440 if (!tmpbuf)
1441 return v4lconvert_oom_error(data);
1442
1443 v4lconvert_nv16_to_yuyv(src, tmpbuf, width, height, bytesperline);
1444 src_pix_fmt = V4L2_PIX_FMT_YUYV;
1445 src = tmpbuf;
1446 bytesperline = width * 2;
1447 /* fall through */
1448 }
1449 case V4L2_PIX_FMT_YUYV:
1450 if (src_size < (width * height * 2)) {
1451 V4LCONVERT_ERR("short yuyv data frame\n");
1452 errno = EPIPE;
1453 result = -1;
1454 }
1455 switch (dest_pix_fmt) {
1456 case V4L2_PIX_FMT_RGB24:
1457 v4lconvert_yuyv_to_rgb24(src, dest, width, height, bytesperline);
1458 break;
1459 case V4L2_PIX_FMT_BGR24:
1460 v4lconvert_yuyv_to_bgr24(src, dest, width, height, bytesperline);
1461 break;
1462 case V4L2_PIX_FMT_YUV420:
1463 v4lconvert_yuyv_to_yuv420(src, dest, width, height, bytesperline, 0);
1464 break;
1465 case V4L2_PIX_FMT_YVU420:
1466 v4lconvert_yuyv_to_yuv420(src, dest, width, height, bytesperline, 1);
1467 break;
1468 }
1469 break;
1470
1471 case V4L2_PIX_FMT_NV61: {
1472 unsigned char *tmpbuf;
1473
1474 tmpbuf = v4lconvert_alloc_buffer(width * height * 2,
1475 &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
1476 if (!tmpbuf)
1477 return v4lconvert_oom_error(data);
1478
1479 /* Note NV61 is NV16 with U and V swapped so this becomes yvyu. */
1480 v4lconvert_nv16_to_yuyv(src, tmpbuf, width, height, bytesperline);
1481 src_pix_fmt = V4L2_PIX_FMT_YVYU;
1482 src = tmpbuf;
1483 bytesperline = width * 2;
1484 /* fall through */
1485 }
1486 case V4L2_PIX_FMT_YVYU:
1487 if (src_size < (width * height * 2)) {
1488 V4LCONVERT_ERR("short yvyu data frame\n");
1489 errno = EPIPE;
1490 result = -1;
1491 }
1492 switch (dest_pix_fmt) {
1493 case V4L2_PIX_FMT_RGB24:
1494 v4lconvert_yvyu_to_rgb24(src, dest, width, height, bytesperline);
1495 break;
1496 case V4L2_PIX_FMT_BGR24:
1497 v4lconvert_yvyu_to_bgr24(src, dest, width, height, bytesperline);
1498 break;
1499 case V4L2_PIX_FMT_YUV420:
1500 /* Note we use yuyv_to_yuv420 not v4lconvert_yvyu_to_yuv420,
1501 with the last argument reversed to make it have as we want */
1502 v4lconvert_yuyv_to_yuv420(src, dest, width, height, bytesperline, 1);
1503 break;
1504 case V4L2_PIX_FMT_YVU420:
1505 v4lconvert_yuyv_to_yuv420(src, dest, width, height, bytesperline, 0);
1506 break;
1507 }
1508 break;
1509
1510 case V4L2_PIX_FMT_UYVY:
1511 if (src_size < (width * height * 2)) {
1512 V4LCONVERT_ERR("short uyvy data frame\n");
1513 errno = EPIPE;
1514 result = -1;
1515 }
1516 switch (dest_pix_fmt) {
1517 case V4L2_PIX_FMT_RGB24:
1518 v4lconvert_uyvy_to_rgb24(src, dest, width, height, bytesperline);
1519 break;
1520 case V4L2_PIX_FMT_BGR24:
1521 v4lconvert_uyvy_to_bgr24(src, dest, width, height, bytesperline);
1522 break;
1523 case V4L2_PIX_FMT_YUV420:
1524 v4lconvert_uyvy_to_yuv420(src, dest, width, height, bytesperline, 0);
1525 break;
1526 case V4L2_PIX_FMT_YVU420:
1527 v4lconvert_uyvy_to_yuv420(src, dest, width, height, bytesperline, 1);
1528 break;
1529 }
1530 break;
1531 case V4L2_PIX_FMT_HSV24:
1532 if (src_size < (width * height * 3)) {
1533 V4LCONVERT_ERR("short hsv24 data frame\n");
1534 errno = EPIPE;
1535 result = -1;
1536 }
1537 switch (dest_pix_fmt) {
1538 case V4L2_PIX_FMT_RGB24:
1539 v4lconvert_hsv_to_rgb24(src, dest, width, height, 0,
1540 24, fmt->fmt.pix.hsv_enc);
1541 break;
1542 case V4L2_PIX_FMT_BGR24:
1543 v4lconvert_hsv_to_rgb24(src, dest, width, height, 1,
1544 24, fmt->fmt.pix.hsv_enc);
1545 break;
1546 case V4L2_PIX_FMT_YUV420:
1547 v4lconvert_hsv_to_rgb24(src, dest, width, height, 0,
1548 24, fmt->fmt.pix.hsv_enc);
1549 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 0, 3);
1550 break;
1551 case V4L2_PIX_FMT_YVU420:
1552 v4lconvert_hsv_to_rgb24(src, dest, width, height, 0,
1553 24, fmt->fmt.pix.hsv_enc);
1554 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 1, 3);
1555 break;
1556 }
1557
1558 break;
1559
1560 case V4L2_PIX_FMT_HSV32:
1561 if (src_size < (width * height * 4)) {
1562 V4LCONVERT_ERR("short hsv32 data frame\n");
1563 errno = EPIPE;
1564 result = -1;
1565 }
1566 switch (dest_pix_fmt) {
1567 case V4L2_PIX_FMT_RGB24:
1568 v4lconvert_hsv_to_rgb24(src, dest, width, height, 0,
1569 32, fmt->fmt.pix.hsv_enc);
1570 break;
1571 case V4L2_PIX_FMT_BGR24:
1572 v4lconvert_hsv_to_rgb24(src, dest, width, height, 1,
1573 32, fmt->fmt.pix.hsv_enc);
1574 break;
1575 case V4L2_PIX_FMT_YUV420:
1576 v4lconvert_hsv_to_rgb24(src, dest, width, height, 0,
1577 32, fmt->fmt.pix.hsv_enc);
1578 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 0, 3);
1579 break;
1580 case V4L2_PIX_FMT_YVU420:
1581 v4lconvert_hsv_to_rgb24(src, dest, width, height, 0,
1582 32, fmt->fmt.pix.hsv_enc);
1583 v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 1, 3);
1584 break;
1585 }
1586
1587 break;
1588
1589
1590
1591 default:
1592 V4LCONVERT_ERR("Unknown src format in conversion\n");
1593 errno = EINVAL;
1594 return -1;
1595 }
1596
1597 fmt->fmt.pix.pixelformat = dest_pix_fmt;
1598 v4lconvert_fixup_fmt(fmt);
1599
1600 return result;
1601 }
1602
v4lconvert_convert(struct v4lconvert_data * data,const struct v4l2_format * src_fmt,const struct v4l2_format * dest_fmt,unsigned char * src,int src_size,unsigned char * dest,int dest_size)1603 int v4lconvert_convert(struct v4lconvert_data *data,
1604 const struct v4l2_format *src_fmt, /* in */
1605 const struct v4l2_format *dest_fmt, /* in */
1606 unsigned char *src, int src_size, unsigned char *dest, int dest_size)
1607 {
1608 int res, dest_needed, temp_needed, processing, convert = 0;
1609 int rotate90, vflip, hflip, crop;
1610 unsigned char *convert1_dest = dest;
1611 int convert1_dest_size = dest_size;
1612 unsigned char *convert2_src = src, *convert2_dest = dest;
1613 int convert2_dest_size = dest_size;
1614 unsigned char *rotate90_src = src, *rotate90_dest = dest;
1615 unsigned char *flip_src = src, *flip_dest = dest;
1616 unsigned char *crop_src = src;
1617 struct v4l2_format my_src_fmt = *src_fmt;
1618 struct v4l2_format my_dest_fmt = *dest_fmt;
1619
1620 processing = v4lprocessing_pre_processing(data->processing);
1621 rotate90 = data->control_flags & V4LCONTROL_ROTATED_90_JPEG;
1622 hflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_HFLIP);
1623 vflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_VFLIP);
1624 crop = my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width ||
1625 my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height;
1626
1627 if (/* If no conversion/processing is needed */
1628 (src_fmt->fmt.pix.pixelformat == dest_fmt->fmt.pix.pixelformat &&
1629 !processing && !rotate90 && !hflip && !vflip && !crop) ||
1630 /* or if we should do processing/rotating/flipping but the app tries to
1631 use the native cam format, we just return an unprocessed frame copy */
1632 !v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) {
1633 int to_copy = MIN(dest_size, src_size);
1634 memcpy(dest, src, to_copy);
1635 return to_copy;
1636 }
1637
1638 /* sanity check, is the dest buffer large enough? */
1639 switch (my_dest_fmt.fmt.pix.pixelformat) {
1640 case V4L2_PIX_FMT_RGB24:
1641 case V4L2_PIX_FMT_BGR24:
1642 dest_needed = my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3;
1643 temp_needed = my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
1644 break;
1645 case V4L2_PIX_FMT_YUV420:
1646 case V4L2_PIX_FMT_YVU420:
1647 dest_needed =
1648 my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3 / 2;
1649 temp_needed =
1650 my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3 / 2;
1651 break;
1652 default:
1653 V4LCONVERT_ERR("Unknown dest format in conversion\n");
1654 errno = EINVAL;
1655 return -1;
1656 }
1657
1658 if (dest_size < dest_needed) {
1659 V4LCONVERT_ERR("destination buffer too small (%d < %d)\n",
1660 dest_size, dest_needed);
1661 errno = EFAULT;
1662 return -1;
1663 }
1664
1665
1666 /* Sometimes we need foo -> rgb -> bar as video processing (whitebalance,
1667 etc.) can only be done on rgb data */
1668 if (processing && v4lconvert_processing_needs_double_conversion(
1669 my_src_fmt.fmt.pix.pixelformat,
1670 my_dest_fmt.fmt.pix.pixelformat))
1671 convert = 2;
1672 else if (my_dest_fmt.fmt.pix.pixelformat !=
1673 my_src_fmt.fmt.pix.pixelformat ||
1674 /* Special case if we do not need to do conversion, but we
1675 are not doing any other step involving copying either,
1676 force going through convert_pixfmt to copy the data from
1677 source to dest */
1678 (!rotate90 && !hflip && !vflip && !crop))
1679 convert = 1;
1680
1681 /* convert_pixfmt (only if convert == 2) -> processing -> convert_pixfmt ->
1682 rotate -> flip -> crop, all steps are optional */
1683 if (convert == 2) {
1684 convert1_dest = v4lconvert_alloc_buffer(
1685 my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3,
1686 &data->convert1_buf, &data->convert1_buf_size);
1687 if (!convert1_dest)
1688 return v4lconvert_oom_error(data);
1689
1690 convert1_dest_size =
1691 my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
1692 convert2_src = convert1_dest;
1693 }
1694
1695 if (convert && (rotate90 || hflip || vflip || crop)) {
1696 convert2_dest = v4lconvert_alloc_buffer(temp_needed,
1697 &data->convert2_buf, &data->convert2_buf_size);
1698 if (!convert2_dest)
1699 return v4lconvert_oom_error(data);
1700
1701 convert2_dest_size = temp_needed;
1702 rotate90_src = flip_src = crop_src = convert2_dest;
1703 }
1704
1705 if (rotate90 && (hflip || vflip || crop)) {
1706 rotate90_dest = v4lconvert_alloc_buffer(temp_needed,
1707 &data->rotate90_buf, &data->rotate90_buf_size);
1708 if (!rotate90_dest)
1709 return v4lconvert_oom_error(data);
1710
1711 flip_src = crop_src = rotate90_dest;
1712 }
1713
1714 if ((vflip || hflip) && crop) {
1715 flip_dest = v4lconvert_alloc_buffer(temp_needed, &data->flip_buf,
1716 &data->flip_buf_size);
1717 if (!flip_dest)
1718 return v4lconvert_oom_error(data);
1719
1720 crop_src = flip_dest;
1721 }
1722
1723 /* Done setting sources / dest and allocating intermediate buffers,
1724 real conversion / processing / ... starts here. */
1725 if (convert == 2) {
1726 res = v4lconvert_convert_pixfmt(data, src, src_size,
1727 convert1_dest, convert1_dest_size,
1728 &my_src_fmt,
1729 V4L2_PIX_FMT_RGB24);
1730 if (res)
1731 return res;
1732
1733 src_size = my_src_fmt.fmt.pix.sizeimage;
1734 }
1735
1736 if (processing)
1737 v4lprocessing_processing(data->processing, convert2_src, &my_src_fmt);
1738
1739 if (convert) {
1740 res = v4lconvert_convert_pixfmt(data, convert2_src, src_size,
1741 convert2_dest, convert2_dest_size,
1742 &my_src_fmt,
1743 my_dest_fmt.fmt.pix.pixelformat);
1744 if (res)
1745 return res;
1746
1747 src_size = my_src_fmt.fmt.pix.sizeimage;
1748
1749 /* We call processing here again in case the source format was not
1750 rgb, but the dest is. v4lprocessing checks it self it only actually
1751 does the processing once per frame. */
1752 if (processing)
1753 v4lprocessing_processing(data->processing, convert2_dest, &my_src_fmt);
1754 }
1755
1756 if (rotate90)
1757 v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt);
1758
1759 if (hflip || vflip)
1760 v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, hflip, vflip);
1761
1762 if (crop)
1763 v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt);
1764
1765 return dest_needed;
1766 }
1767
v4lconvert_get_error_message(struct v4lconvert_data * data)1768 const char *v4lconvert_get_error_message(struct v4lconvert_data *data)
1769 {
1770 return data->error_msg;
1771 }
1772
v4lconvert_get_framesizes(struct v4lconvert_data * data,unsigned int pixelformat,int index)1773 static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
1774 unsigned int pixelformat, int index)
1775 {
1776 int i, j, match;
1777 struct v4l2_frmsizeenum frmsize = { .pixel_format = pixelformat };
1778
1779 for (i = 0; ; i++) {
1780 frmsize.index = i;
1781 if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
1782 VIDIOC_ENUM_FRAMESIZES, &frmsize))
1783 break;
1784
1785 /* We got a framesize, check we don't have the same one already */
1786 match = 0;
1787 for (j = 0; j < data->no_framesizes; j++) {
1788 if (frmsize.type != data->framesizes[j].type)
1789 continue;
1790
1791 switch (frmsize.type) {
1792 case V4L2_FRMSIZE_TYPE_DISCRETE:
1793 if (!memcmp(&frmsize.discrete, &data->framesizes[j].discrete,
1794 sizeof(frmsize.discrete)))
1795 match = 1;
1796 break;
1797 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1798 case V4L2_FRMSIZE_TYPE_STEPWISE:
1799 if (!memcmp(&frmsize.stepwise, &data->framesizes[j].stepwise,
1800 sizeof(frmsize.stepwise)))
1801 match = 1;
1802 break;
1803 }
1804 if (match)
1805 break;
1806 }
1807 /* Add this framesize if it is not already in our list */
1808 if (!match) {
1809 if (data->no_framesizes == V4LCONVERT_MAX_FRAMESIZES) {
1810 fprintf(stderr, "libv4lconvert: warning more framesizes than I can handle!\n");
1811 return;
1812 }
1813 data->framesizes[data->no_framesizes].type = frmsize.type;
1814 data->framesize_supported_src_formats[data->no_framesizes] = 1ULL << index;
1815
1816 switch (frmsize.type) {
1817 case V4L2_FRMSIZE_TYPE_DISCRETE:
1818 data->framesizes[data->no_framesizes].discrete = frmsize.discrete;
1819 break;
1820 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1821 case V4L2_FRMSIZE_TYPE_STEPWISE:
1822 data->framesizes[data->no_framesizes].stepwise = frmsize.stepwise;
1823 break;
1824 }
1825 data->no_framesizes++;
1826 } else {
1827 data->framesize_supported_src_formats[j] |= 1ULL << index;
1828 }
1829 }
1830 }
1831
v4lconvert_enum_framesizes(struct v4lconvert_data * data,struct v4l2_frmsizeenum * frmsize)1832 int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
1833 struct v4l2_frmsizeenum *frmsize)
1834 {
1835 if (!v4lconvert_supported_dst_format(frmsize->pixel_format)) {
1836 if (v4lconvert_supported_dst_fmt_only(data)) {
1837 errno = EINVAL;
1838 return -1;
1839 }
1840 return data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
1841 VIDIOC_ENUM_FRAMESIZES, frmsize);
1842 }
1843
1844 if (frmsize->index >= data->no_framesizes) {
1845 errno = EINVAL;
1846 return -1;
1847 }
1848
1849 frmsize->type = data->framesizes[frmsize->index].type;
1850 memset(frmsize->reserved, 0, sizeof(frmsize->reserved));
1851 switch (frmsize->type) {
1852 case V4L2_FRMSIZE_TYPE_DISCRETE:
1853 frmsize->discrete = data->framesizes[frmsize->index].discrete;
1854 /* Apply the same rounding algorithm as v4lconvert_try_format */
1855 frmsize->discrete.width &= ~7;
1856 frmsize->discrete.height &= ~1;
1857 break;
1858 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1859 case V4L2_FRMSIZE_TYPE_STEPWISE:
1860 frmsize->stepwise = data->framesizes[frmsize->index].stepwise;
1861 break;
1862 }
1863
1864 return 0;
1865 }
1866
v4lconvert_enum_frameintervals(struct v4lconvert_data * data,struct v4l2_frmivalenum * frmival)1867 int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
1868 struct v4l2_frmivalenum *frmival)
1869 {
1870 int res;
1871 struct v4l2_format src_fmt, dest_fmt;
1872
1873 if (!v4lconvert_supported_dst_format(frmival->pixel_format)) {
1874 if (v4lconvert_supported_dst_fmt_only(data)) {
1875 errno = EINVAL;
1876 return -1;
1877 }
1878 res = data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
1879 VIDIOC_ENUM_FRAMEINTERVALS, frmival);
1880 if (res)
1881 V4LCONVERT_ERR("%s\n", strerror(errno));
1882 return res;
1883 }
1884
1885 /* Check which format we will be using to convert to frmival->pixel_format */
1886 memset(&dest_fmt, 0, sizeof(dest_fmt));
1887 dest_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1888 dest_fmt.fmt.pix.pixelformat = frmival->pixel_format;
1889 dest_fmt.fmt.pix.width = frmival->width;
1890 dest_fmt.fmt.pix.height = frmival->height;
1891 res = v4lconvert_try_format(data, &dest_fmt, &src_fmt);
1892 if (res) {
1893 V4LCONVERT_ERR("trying format: %s\n", strerror(errno));
1894 return res;
1895 }
1896
1897 /* Check the requested format is supported exactly as requested */
1898 if (dest_fmt.fmt.pix.pixelformat != frmival->pixel_format ||
1899 dest_fmt.fmt.pix.width != frmival->width ||
1900 dest_fmt.fmt.pix.height != frmival->height) {
1901 int frmival_pixformat = frmival->pixel_format;
1902 int dest_pixformat = dest_fmt.fmt.pix.pixelformat;
1903
1904 V4LCONVERT_ERR("Could not find matching framesize for: %c%c%c%c %dx%d "
1905 "closest match: %c%c%c%c %dx%d\n",
1906 frmival_pixformat & 0xff,
1907 (frmival_pixformat >> 8) & 0xff,
1908 (frmival_pixformat >> 16) & 0xff,
1909 frmival_pixformat >> 24,
1910 frmival->width, frmival->height,
1911 dest_pixformat & 0xff,
1912 (dest_pixformat >> 8) & 0xff,
1913 (dest_pixformat >> 16) & 0xff,
1914 dest_pixformat >> 24,
1915 dest_fmt.fmt.pix.width , dest_fmt.fmt.pix.height);
1916 errno = EINVAL;
1917 return -1;
1918 }
1919
1920 /* Enumerate the frameintervals of the source format we will be using */
1921 frmival->pixel_format = src_fmt.fmt.pix.pixelformat;
1922 frmival->width = src_fmt.fmt.pix.width;
1923 frmival->height = src_fmt.fmt.pix.height;
1924 res = data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
1925 VIDIOC_ENUM_FRAMEINTERVALS, frmival);
1926 if (res) {
1927 int dest_pixfmt = dest_fmt.fmt.pix.pixelformat;
1928 int src_pixfmt = src_fmt.fmt.pix.pixelformat;
1929
1930 V4LCONVERT_ERR("Could not enum frameival index: %d for: %c%c%c%c %dx%d "
1931 "using src: %c%c%c%c %dx%d, error: %s\n",
1932 frmival->index,
1933 dest_pixfmt & 0xff,
1934 (dest_pixfmt >> 8) & 0xff,
1935 (dest_pixfmt >> 16) & 0xff,
1936 dest_pixfmt >> 24,
1937 dest_fmt.fmt.pix.width , dest_fmt.fmt.pix.height,
1938 src_pixfmt & 0xff,
1939 (src_pixfmt >> 8) & 0xff,
1940 (src_pixfmt >> 16) & 0xff,
1941 src_pixfmt >> 24,
1942 src_fmt.fmt.pix.width, src_fmt.fmt.pix.height, strerror(errno));
1943 }
1944
1945 /* Restore the requested format in the frmival struct */
1946 frmival->pixel_format = dest_fmt.fmt.pix.pixelformat;
1947 frmival->width = dest_fmt.fmt.pix.width;
1948 frmival->height = dest_fmt.fmt.pix.height;
1949
1950 return res;
1951 }
1952
v4lconvert_vidioc_queryctrl(struct v4lconvert_data * data,void * arg)1953 int v4lconvert_vidioc_queryctrl(struct v4lconvert_data *data, void *arg)
1954 {
1955 return v4lcontrol_vidioc_queryctrl(data->control, arg);
1956 }
1957
v4lconvert_vidioc_g_ctrl(struct v4lconvert_data * data,void * arg)1958 int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data, void *arg)
1959 {
1960 return v4lcontrol_vidioc_g_ctrl(data->control, arg);
1961 }
1962
v4lconvert_vidioc_s_ctrl(struct v4lconvert_data * data,void * arg)1963 int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data, void *arg)
1964 {
1965 return v4lcontrol_vidioc_s_ctrl(data->control, arg);
1966 }
1967
v4lconvert_vidioc_g_ext_ctrls(struct v4lconvert_data * data,void * arg)1968 int v4lconvert_vidioc_g_ext_ctrls(struct v4lconvert_data *data, void *arg)
1969 {
1970 return v4lcontrol_vidioc_g_ext_ctrls(data->control, arg);
1971 }
1972
v4lconvert_vidioc_try_ext_ctrls(struct v4lconvert_data * data,void * arg)1973 int v4lconvert_vidioc_try_ext_ctrls(struct v4lconvert_data *data, void *arg)
1974 {
1975 return v4lcontrol_vidioc_try_ext_ctrls(data->control, arg);
1976 }
1977
v4lconvert_vidioc_s_ext_ctrls(struct v4lconvert_data * data,void * arg)1978 int v4lconvert_vidioc_s_ext_ctrls(struct v4lconvert_data *data, void *arg)
1979 {
1980 return v4lcontrol_vidioc_s_ext_ctrls(data->control, arg);
1981 }
1982
v4lconvert_get_fps(struct v4lconvert_data * data)1983 int v4lconvert_get_fps(struct v4lconvert_data *data)
1984 {
1985 return data->fps;
1986 }
1987
v4lconvert_set_fps(struct v4lconvert_data * data,int fps)1988 void v4lconvert_set_fps(struct v4lconvert_data *data, int fps)
1989 {
1990 data->fps = fps;
1991 }
1992