2
# (C) 2008-2011 Hans de Goede <hdegoede@redhat.com>
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.
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.
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
24
#include <sys/types.h>
25
#include "libv4lconvert.h"
26
#include "libv4lconvert-priv.h"
27
#include "libv4lsyscall-priv.h"
29
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
31
static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
32
unsigned int pixelformat, int index);
34
/* Note for proper functioning of v4lconvert_enum_fmt the first entries in
35
supported_src_pixfmts must match with the entries in supported_dst_pixfmts */
36
#define SUPPORTED_DST_PIXFMTS \
37
/* fourcc bpp rgb yuv needs */ \
38
/* rank rank conversion */ \
39
{ V4L2_PIX_FMT_RGB24, 24, 1, 5, 0 }, \
40
{ V4L2_PIX_FMT_BGR24, 24, 1, 5, 0 }, \
41
{ V4L2_PIX_FMT_YUV420, 12, 6, 1, 0 }, \
42
{ V4L2_PIX_FMT_YVU420, 12, 6, 1, 0 }
44
static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
45
SUPPORTED_DST_PIXFMTS,
46
/* packed rgb formats */
47
{ V4L2_PIX_FMT_RGB565, 16, 4, 6, 0 },
48
/* yuv 4:2:2 formats */
49
{ V4L2_PIX_FMT_YUYV, 16, 5, 4, 0 },
50
{ V4L2_PIX_FMT_YVYU, 16, 5, 4, 0 },
51
{ V4L2_PIX_FMT_UYVY, 16, 5, 4, 0 },
52
/* yuv 4:2:0 formats */
53
{ V4L2_PIX_FMT_SPCA501, 12, 6, 3, 1 },
54
{ V4L2_PIX_FMT_SPCA505, 12, 6, 3, 1 },
55
{ V4L2_PIX_FMT_SPCA508, 12, 6, 3, 1 },
56
{ V4L2_PIX_FMT_CIT_YYVYUY, 12, 6, 3, 1 },
57
{ V4L2_PIX_FMT_KONICA420, 12, 6, 3, 1 },
58
{ V4L2_PIX_FMT_SN9C20X_I420, 12, 6, 3, 1 },
59
{ V4L2_PIX_FMT_M420, 12, 6, 3, 1 },
60
{ V4L2_PIX_FMT_HM12, 12, 6, 3, 1 },
61
{ V4L2_PIX_FMT_CPIA1, 0, 6, 3, 1 },
62
/* JPEG and variants */
63
{ V4L2_PIX_FMT_MJPEG, 0, 7, 7, 0 },
64
{ V4L2_PIX_FMT_JPEG, 0, 7, 7, 0 },
65
{ V4L2_PIX_FMT_PJPG, 0, 7, 7, 1 },
66
{ V4L2_PIX_FMT_JPGL, 0, 7, 7, 1 },
67
{ V4L2_PIX_FMT_OV511, 0, 7, 7, 1 },
68
{ V4L2_PIX_FMT_OV518, 0, 7, 7, 1 },
69
/* uncompressed bayer */
70
{ V4L2_PIX_FMT_SBGGR8, 8, 8, 8, 1 },
71
{ V4L2_PIX_FMT_SGBRG8, 8, 8, 8, 1 },
72
{ V4L2_PIX_FMT_SGRBG8, 8, 8, 8, 1 },
73
{ V4L2_PIX_FMT_SRGGB8, 8, 8, 8, 1 },
74
{ V4L2_PIX_FMT_STV0680, 8, 8, 8, 1 },
75
/* compressed bayer */
76
{ V4L2_PIX_FMT_SPCA561, 0, 9, 9, 1 },
77
{ V4L2_PIX_FMT_SN9C10X, 0, 9, 9, 1 },
78
{ V4L2_PIX_FMT_SN9C2028, 0, 9, 9, 1 },
79
{ V4L2_PIX_FMT_PAC207, 0, 9, 9, 1 },
80
{ V4L2_PIX_FMT_MR97310A, 0, 9, 9, 1 },
81
{ V4L2_PIX_FMT_SQ905C, 0, 9, 9, 1 },
83
{ V4L2_PIX_FMT_SE401, 0, 8, 9, 1 },
85
{ V4L2_PIX_FMT_GREY, 8, 20, 20, 0 },
86
{ V4L2_PIX_FMT_Y10BPACK, 10, 20, 20, 0 },
89
static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = {
93
/* List of well known resolutions which we can get by cropping somewhat larger
95
static const int v4lconvert_crop_res[][2] = {
96
/* low res VGA resolutions, can be made by software cropping SIF resolutions
97
for cam/drivers which do not support this in hardware */
100
/* Some CIF cams (with vv6410 sensor) have slightly larger then usual CIF
101
resolutions, make regular CIF resolutions available on these by sw crop */
106
struct v4lconvert_data *v4lconvert_create(int fd)
109
struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data));
110
struct v4l2_capability cap;
111
/* This keeps tracks of devices which have only formats for which apps
112
most likely will need conversion and we can thus safely add software
113
processing controls without a performance impact. */
114
int always_needs_conversion = 1;
117
fprintf(stderr, "libv4lconvert: error: out of memory!\n");
122
data->decompress_pid = -1;
125
/* Check supported formats */
127
struct v4l2_fmtdesc fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
131
if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, &fmt))
134
for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++)
135
if (fmt.pixelformat == supported_src_pixfmts[j].fmt)
138
if (j < ARRAY_SIZE(supported_src_pixfmts)) {
139
data->supported_src_formats |= 1 << j;
140
v4lconvert_get_framesizes(data, fmt.pixelformat, j);
141
if (!supported_src_pixfmts[j].needs_conversion)
142
always_needs_conversion = 0;
144
always_needs_conversion = 0;
147
data->no_formats = i;
149
/* Check if this cam has any special flags */
150
if (SYS_IOCTL(data->fd, VIDIOC_QUERYCAP, &cap) == 0) {
151
if (!strcmp((char *)cap.driver, "uvcvideo"))
152
data->flags |= V4LCONVERT_IS_UVC;
154
if ((cap.capabilities & 0xff) & ~V4L2_CAP_VIDEO_CAPTURE)
155
always_needs_conversion = 0;
158
data->control = v4lcontrol_create(fd, always_needs_conversion);
159
if (!data->control) {
163
data->bandwidth = v4lcontrol_get_bandwidth(data->control);
164
data->control_flags = v4lcontrol_get_flags(data->control);
165
if (data->control_flags & V4LCONTROL_FORCE_TINYJPEG)
166
data->flags |= V4LCONVERT_USE_TINYJPEG;
168
data->processing = v4lprocessing_create(fd, data->control);
169
if (!data->processing) {
170
v4lcontrol_destroy(data->control);
178
void v4lconvert_destroy(struct v4lconvert_data *data)
180
v4lprocessing_destroy(data->processing);
181
v4lcontrol_destroy(data->control);
182
if (data->tinyjpeg) {
183
unsigned char *comps[3] = { NULL, NULL, NULL };
185
tinyjpeg_set_components(data->tinyjpeg, comps, 3);
186
tinyjpeg_free(data->tinyjpeg);
188
if (data->cinfo_initialized)
189
jpeg_destroy_decompress(&data->cinfo);
190
v4lconvert_helper_cleanup(data);
191
free(data->convert1_buf);
192
free(data->convert2_buf);
193
free(data->rotate90_buf);
194
free(data->flip_buf);
195
free(data->convert_pixfmt_buf);
196
free(data->previous_frame);
200
int v4lconvert_supported_dst_format(unsigned int pixelformat)
204
for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
205
if (supported_dst_pixfmts[i].fmt == pixelformat)
208
return i != ARRAY_SIZE(supported_dst_pixfmts);
211
int v4lconvert_supported_dst_fmt_only(struct v4lconvert_data *data)
213
return v4lcontrol_needs_conversion(data->control) &&
214
data->supported_src_formats;
217
/* See libv4lconvert.h for description of in / out parameters */
218
int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
220
int i, no_faked_fmts = 0;
221
unsigned int faked_fmts[ARRAY_SIZE(supported_dst_pixfmts)];
223
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
224
(!v4lconvert_supported_dst_fmt_only(data) &&
225
fmt->index < data->no_formats))
226
return SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, fmt);
228
for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
229
if (v4lconvert_supported_dst_fmt_only(data) ||
230
!(data->supported_src_formats & (1 << i))) {
231
faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i].fmt;
235
if (!v4lconvert_supported_dst_fmt_only(data))
236
i = fmt->index - data->no_formats;
240
if (i >= no_faked_fmts) {
245
fmt->flags = V4L2_FMT_FLAG_EMULATED;
246
fmt->pixelformat = faked_fmts[i];
247
fmt->description[0] = faked_fmts[i] & 0xff;
248
fmt->description[1] = (faked_fmts[i] >> 8) & 0xff;
249
fmt->description[2] = (faked_fmts[i] >> 16) & 0xff;
250
fmt->description[3] = faked_fmts[i] >> 24;
251
fmt->description[4] = '\0';
252
memset(fmt->reserved, 0, sizeof(fmt->reserved));
257
/* This function returns a value to rank (sort) source format by preference
258
when multiple source formats are available for a certain resolution, the
259
source format for which this function returns the lowest value wins.
261
This function uses the rgb_rank resp. yuv_rank values as a base when
262
converting to rgb32 resp. yuv420. The initial ranks range from 1 - 10,
263
the initial rank purely expresses the CPU cost of doing the conversion, the
264
ranking algorithm will give a penalty of 10 points if
265
(width * height * fps * bpp / 8) > bandwidth
266
thus disqualifying a src format which causes the bandwidth to be exceeded,
267
except when all of them cause this.
269
Note grey scale formats start at 20 rather then 1-10, because we want to
270
never autoselect them, unless they are the only choice */
271
static int v4lconvert_get_rank(struct v4lconvert_data *data,
272
int src_index, int src_width, int src_height,
273
unsigned int dest_pixelformat)
275
int needed, rank = 0;
277
switch (dest_pixelformat) {
278
case V4L2_PIX_FMT_RGB24:
279
case V4L2_PIX_FMT_BGR24:
280
rank = supported_src_pixfmts[src_index].rgb_rank;
282
case V4L2_PIX_FMT_YUV420:
283
case V4L2_PIX_FMT_YVU420:
284
rank = supported_src_pixfmts[src_index].yuv_rank;
288
/* So that if both rgb32 and bgr32 are supported, or both yuv420 and
289
yvu420 the right one wins */
290
if (supported_src_pixfmts[src_index].fmt == dest_pixelformat)
293
/* check bandwidth needed */
294
needed = src_width * src_height * data->fps *
295
supported_src_pixfmts[src_index].bpp / 8;
296
if (data->bandwidth && needed > data->bandwidth)
299
printf("ranked: %c%c%c%c for %dx%d @ %d fps, needed: %d, bandwidth: %d, rank: %d\n",
300
supported_src_pixfmts[src_index].fmt & 0xff,
301
(supported_src_pixfmts[src_index].fmt >> 8) & 0xff,
302
(supported_src_pixfmts[src_index].fmt >> 16) & 0xff,
303
supported_src_pixfmts[src_index].fmt >> 24, src_width,
304
src_height, data->fps, needed, data->bandwidth, rank);
309
/* Find out what format to use based on the (cached) results of enum
310
framesizes instead of doing a zillion try_fmt calls. This function
311
currently is intended for use with UVC cams only. This is esp.
312
important for UVC based cams as doing try_fmt there actually causes I/O */
313
static int v4lconvert_do_try_format_uvc(struct v4lconvert_data *data,
314
struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
317
unsigned int closest_fmt_size_diff = -1;
318
int best_framesize = 0;/* Just use the first format if no small enough one */
322
for (i = 0; i < data->no_framesizes; i++) {
323
if (data->framesizes[i].discrete.width <= dest_fmt->fmt.pix.width &&
324
data->framesizes[i].discrete.height <= dest_fmt->fmt.pix.height) {
325
int size_x_diff = dest_fmt->fmt.pix.width -
326
data->framesizes[i].discrete.width;
327
int size_y_diff = dest_fmt->fmt.pix.height -
328
data->framesizes[i].discrete.height;
329
unsigned int size_diff = size_x_diff * size_x_diff +
330
size_y_diff * size_y_diff;
332
if (size_diff < closest_fmt_size_diff) {
333
closest_fmt_size_diff = size_diff;
339
for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
340
/* is this format supported? */
341
if (!(data->framesizes[best_framesize].pixel_format & (1 << i)))
344
/* Note the hardcoded use of discrete is based on this function
345
only getting called for uvc devices */
346
rank = v4lconvert_get_rank(data, i,
347
data->framesizes[best_framesize].discrete.width,
348
data->framesizes[best_framesize].discrete.height,
349
dest_fmt->fmt.pix.pixelformat);
350
if (rank < best_rank) {
352
best_format = supported_src_pixfmts[i].fmt;
356
dest_fmt->fmt.pix.width = data->framesizes[best_framesize].discrete.width;
357
dest_fmt->fmt.pix.height = data->framesizes[best_framesize].discrete.height;
358
dest_fmt->fmt.pix.field = V4L2_FIELD_NONE; /* UVC has no fields */
359
/* Not pretty, the pwc driver doesn't fill these in try_fmt either though,
360
so we should be able to get away with this. */
361
dest_fmt->fmt.pix.bytesperline = 0;
362
dest_fmt->fmt.pix.sizeimage = 0;
363
dest_fmt->fmt.pix.colorspace = 0;
364
dest_fmt->fmt.pix.priv = 0;
366
*src_fmt = *dest_fmt;
367
src_fmt->fmt.pix.pixelformat = best_format;
372
static int v4lconvert_do_try_format(struct v4lconvert_data *data,
373
struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
375
int i, size_x_diff, size_y_diff, rank, best_rank = 0;
376
unsigned int size_diff, closest_fmt_size_diff = -1;
377
unsigned int desired_pixfmt = dest_fmt->fmt.pix.pixelformat;
378
struct v4l2_format try_fmt, closest_fmt = { .type = 0 };
380
if (data->flags & V4LCONVERT_IS_UVC)
381
return v4lconvert_do_try_format_uvc(data, dest_fmt, src_fmt);
383
for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
384
/* is this format supported? */
385
if (!(data->supported_src_formats & (1 << i)))
389
try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt;
390
if (SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, &try_fmt))
393
if (try_fmt.fmt.pix.pixelformat !=
394
supported_src_pixfmts[i].fmt)
397
/* Did we get a better match then before? */
398
size_x_diff = (int)try_fmt.fmt.pix.width -
399
(int)dest_fmt->fmt.pix.width;
400
size_y_diff = (int)try_fmt.fmt.pix.height -
401
(int)dest_fmt->fmt.pix.height;
402
size_diff = size_x_diff * size_x_diff +
403
size_y_diff * size_y_diff;
405
rank = v4lconvert_get_rank(data, i,
406
try_fmt.fmt.pix.width,
407
try_fmt.fmt.pix.height,
409
if (size_diff < closest_fmt_size_diff ||
410
(size_diff == closest_fmt_size_diff && rank < best_rank)) {
411
closest_fmt = try_fmt;
412
closest_fmt_size_diff = size_diff;
417
if (closest_fmt.type == 0)
420
*dest_fmt = closest_fmt;
421
if (closest_fmt.fmt.pix.pixelformat != desired_pixfmt)
422
dest_fmt->fmt.pix.pixelformat = desired_pixfmt;
423
*src_fmt = closest_fmt;
428
void v4lconvert_fixup_fmt(struct v4l2_format *fmt)
430
switch (fmt->fmt.pix.pixelformat) {
431
case V4L2_PIX_FMT_RGB24:
432
case V4L2_PIX_FMT_BGR24:
433
fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * 3;
434
fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3;
436
case V4L2_PIX_FMT_YUV420:
437
case V4L2_PIX_FMT_YVU420:
438
fmt->fmt.pix.bytesperline = fmt->fmt.pix.width;
439
fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3 / 2;
444
/* See libv4lconvert.h for description of in / out parameters */
445
int v4lconvert_try_format(struct v4lconvert_data *data,
446
struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
449
unsigned int desired_width = dest_fmt->fmt.pix.width;
450
unsigned int desired_height = dest_fmt->fmt.pix.height;
451
struct v4l2_format try_src, try_dest, try2_src, try2_dest;
453
if (dest_fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
454
v4lconvert_supported_dst_fmt_only(data) &&
455
!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat))
456
dest_fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
458
try_dest = *dest_fmt;
460
/* Can we do conversion to the requested format & type? */
461
if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) ||
462
dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
463
v4lconvert_do_try_format(data, &try_dest, &try_src)) {
464
result = SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, dest_fmt);
466
*src_fmt = *dest_fmt;
470
/* In case of a non exact resolution match, try again with a slightly larger
471
resolution as some weird devices are not able to crop of the number of
472
extra (border) pixels most sensors have compared to standard resolutions,
473
which we will then just crop of in software */
474
if (try_dest.fmt.pix.width != desired_width ||
475
try_dest.fmt.pix.height != desired_height) {
476
try2_dest = *dest_fmt;
477
try2_dest.fmt.pix.width = desired_width + 7;
478
try2_dest.fmt.pix.height = desired_height + 1;
479
result = v4lconvert_do_try_format(data, &try2_dest, &try2_src);
481
try2_dest.fmt.pix.width >= desired_width &&
482
try2_dest.fmt.pix.width <= desired_width + 7 &&
483
try2_dest.fmt.pix.height >= desired_height &&
484
try2_dest.fmt.pix.height <= desired_height + 1) {
486
try2_dest.fmt.pix.width = desired_width;
487
try2_dest.fmt.pix.height = desired_height;
488
try_dest = try2_dest;
493
/* In case of a non exact resolution match, see if this is a well known
494
resolution some apps are hardcoded too and try to give the app what it
495
asked for by cropping a slightly larger resolution or adding a small
496
black border to a slightly smaller resolution */
497
if (try_dest.fmt.pix.width != desired_width ||
498
try_dest.fmt.pix.height != desired_height) {
499
for (i = 0; i < ARRAY_SIZE(v4lconvert_crop_res); i++) {
500
if (v4lconvert_crop_res[i][0] == desired_width &&
501
v4lconvert_crop_res[i][1] == desired_height) {
502
try2_dest = *dest_fmt;
504
/* Note these are chosen so that cropping to vga res just works for
505
vv6410 sensor cams, which have 356x292 and 180x148 */
506
try2_dest.fmt.pix.width = desired_width * 113 / 100;
507
try2_dest.fmt.pix.height = desired_height * 124 / 100;
508
result = v4lconvert_do_try_format(data, &try2_dest, &try2_src);
510
(/* Add a small black border of max 16 pixels */
511
(try2_dest.fmt.pix.width >= desired_width - 16 &&
512
try2_dest.fmt.pix.width <= desired_width &&
513
try2_dest.fmt.pix.height >= desired_height - 16 &&
514
try2_dest.fmt.pix.height <= desired_height) ||
515
/* Standard cropping to max 80% of actual width / height */
516
(try2_dest.fmt.pix.width >= desired_width &&
517
try2_dest.fmt.pix.width <= desired_width * 5 / 4 &&
518
try2_dest.fmt.pix.height >= desired_height &&
519
try2_dest.fmt.pix.height <= desired_height * 5 / 4) ||
520
/* Downscale 2x + cropping to max 80% of actual width / height */
521
(try2_dest.fmt.pix.width >= desired_width * 2 &&
522
try2_dest.fmt.pix.width <= desired_width * 5 / 2 &&
523
try2_dest.fmt.pix.height >= desired_height * 2 &&
524
try2_dest.fmt.pix.height <= desired_height * 5 / 2))) {
526
try2_dest.fmt.pix.width = desired_width;
527
try2_dest.fmt.pix.height = desired_height;
528
try_dest = try2_dest;
536
/* Some applications / libs (*cough* gstreamer *cough*) will not work
537
correctly with planar YUV formats when the width is not a multiple of 8
538
or the height is not a multiple of 2. With RGB formats these apps require
539
the width to be a multiple of 4. We apply the same rounding to all
540
formats to not end up with 2 close but different resolutions. */
541
try_dest.fmt.pix.width &= ~7;
542
try_dest.fmt.pix.height &= ~1;
544
/* Are we converting / cropping ? */
545
if (try_src.fmt.pix.width != try_dest.fmt.pix.width ||
546
try_src.fmt.pix.height != try_dest.fmt.pix.height ||
547
try_src.fmt.pix.pixelformat != try_dest.fmt.pix.pixelformat)
548
v4lconvert_fixup_fmt(&try_dest);
550
*dest_fmt = try_dest;
557
/* Is conversion necessary ? */
558
int v4lconvert_needs_conversion(struct v4lconvert_data *data,
559
const struct v4l2_format *src_fmt, /* in */
560
const struct v4l2_format *dest_fmt) /* in */
562
if (src_fmt->fmt.pix.width != dest_fmt->fmt.pix.width ||
563
src_fmt->fmt.pix.height != dest_fmt->fmt.pix.height ||
564
src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat ||
565
(v4lcontrol_needs_conversion(data->control) &&
566
v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)))
572
static int v4lconvert_processing_needs_double_conversion(
573
unsigned int src_pix_fmt, unsigned int dest_pix_fmt)
575
switch (src_pix_fmt) {
576
case V4L2_PIX_FMT_RGB24:
577
case V4L2_PIX_FMT_BGR24:
578
case V4L2_PIX_FMT_SPCA561:
579
case V4L2_PIX_FMT_SN9C10X:
580
case V4L2_PIX_FMT_PAC207:
581
case V4L2_PIX_FMT_MR97310A:
582
case V4L2_PIX_FMT_SN9C2028:
583
case V4L2_PIX_FMT_SQ905C:
584
case V4L2_PIX_FMT_SBGGR8:
585
case V4L2_PIX_FMT_SGBRG8:
586
case V4L2_PIX_FMT_SGRBG8:
587
case V4L2_PIX_FMT_SRGGB8:
588
case V4L2_PIX_FMT_STV0680:
591
switch (dest_pix_fmt) {
592
case V4L2_PIX_FMT_RGB24:
593
case V4L2_PIX_FMT_BGR24:
600
unsigned char *v4lconvert_alloc_buffer(int needed,
601
unsigned char **buf, int *buf_size)
603
if (*buf_size < needed) {
605
*buf = malloc(needed);
615
int v4lconvert_oom_error(struct v4lconvert_data *data)
617
V4LCONVERT_ERR("could not allocate memory\n");
622
static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
623
unsigned char *src, int src_size, unsigned char *dest, int dest_size,
624
struct v4l2_format *fmt, unsigned int dest_pix_fmt)
627
unsigned int src_pix_fmt = fmt->fmt.pix.pixelformat;
628
unsigned int width = fmt->fmt.pix.width;
629
unsigned int height = fmt->fmt.pix.height;
631
switch (src_pix_fmt) {
632
/* JPG and variants */
633
case V4L2_PIX_FMT_MJPEG:
634
case V4L2_PIX_FMT_JPEG:
635
if (data->flags & V4LCONVERT_USE_TINYJPEG) {
636
result = v4lconvert_decode_jpeg_tinyjpeg(data,
638
fmt, dest_pix_fmt, 0);
640
result = v4lconvert_decode_jpeg_libjpeg(data,
643
if (result == -1 && errno == EOPNOTSUPP) {
644
/* Fall back to tinyjpeg */
645
jpeg_destroy_decompress(&data->cinfo);
646
data->cinfo_initialized = 0;
647
data->flags |= V4LCONVERT_USE_TINYJPEG;
648
result = v4lconvert_decode_jpeg_tinyjpeg(data,
650
fmt, dest_pix_fmt, 0);
654
case V4L2_PIX_FMT_PJPG:
655
result = v4lconvert_decode_jpeg_tinyjpeg(data, src, src_size,
656
dest, fmt, dest_pix_fmt,
657
TINYJPEG_FLAGS_PIXART_JPEG);
659
case V4L2_PIX_FMT_JPGL:
660
result = v4lconvert_decode_jpgl(src, src_size, dest_pix_fmt,
661
dest, width, height);
664
/* Custom cam specific YUV formats */
665
case V4L2_PIX_FMT_SPCA501:
666
case V4L2_PIX_FMT_SPCA505:
667
case V4L2_PIX_FMT_SPCA508:
668
case V4L2_PIX_FMT_CIT_YYVYUY:
669
case V4L2_PIX_FMT_KONICA420:
670
case V4L2_PIX_FMT_M420:
671
case V4L2_PIX_FMT_SN9C20X_I420:
672
case V4L2_PIX_FMT_CPIA1:
673
case V4L2_PIX_FMT_OV511:
674
case V4L2_PIX_FMT_OV518: {
679
if (dest_pix_fmt != V4L2_PIX_FMT_YUV420 &&
680
dest_pix_fmt != V4L2_PIX_FMT_YVU420) {
681
d = v4lconvert_alloc_buffer(width * height * 3 / 2,
682
&data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
684
return v4lconvert_oom_error(data);
685
d_size = width * height * 3 / 2;
691
if (dest_pix_fmt == V4L2_PIX_FMT_YVU420)
694
switch (src_pix_fmt) {
695
case V4L2_PIX_FMT_SPCA501:
696
v4lconvert_spca501_to_yuv420(src, d, width, height, yvu);
698
case V4L2_PIX_FMT_SPCA505:
699
v4lconvert_spca505_to_yuv420(src, d, width, height, yvu);
701
case V4L2_PIX_FMT_SPCA508:
702
v4lconvert_spca508_to_yuv420(src, d, width, height, yvu);
704
case V4L2_PIX_FMT_CIT_YYVYUY:
705
v4lconvert_cit_yyvyuy_to_yuv420(src, d, width, height, yvu);
707
case V4L2_PIX_FMT_KONICA420:
708
v4lconvert_konica_yuv420_to_yuv420(src, d, width, height, yvu);
710
case V4L2_PIX_FMT_M420:
711
v4lconvert_m420_to_yuv420(src, d, width, height, yvu);
713
case V4L2_PIX_FMT_SN9C20X_I420:
714
v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu);
716
case V4L2_PIX_FMT_CPIA1:
717
if (v4lconvert_cpia1_to_yuv420(data, src, src_size, d,
718
width, height, yvu)) {
719
/* Corrupt frame, better get another one */
724
case V4L2_PIX_FMT_OV511:
725
if (v4lconvert_helper_decompress(data, LIBDIR "/" LIBSUBDIR "/ov511-decomp",
726
src, src_size, d, d_size, width, height, yvu)) {
727
/* Corrupt frame, better get another one */
732
case V4L2_PIX_FMT_OV518:
733
if (v4lconvert_helper_decompress(data, LIBDIR "/" LIBSUBDIR "/ov518-decomp",
734
src, src_size, d, d_size, width, height, yvu)) {
735
/* Corrupt frame, better get another one */
742
switch (dest_pix_fmt) {
743
case V4L2_PIX_FMT_RGB24:
744
v4lconvert_yuv420_to_rgb24(data->convert_pixfmt_buf, dest, width,
747
case V4L2_PIX_FMT_BGR24:
748
v4lconvert_yuv420_to_bgr24(data->convert_pixfmt_buf, dest, width,
755
/* Conexant cx2341x raw video macroblock format */
756
case V4L2_PIX_FMT_HM12:
757
switch (dest_pix_fmt) {
758
case V4L2_PIX_FMT_RGB24:
759
v4lconvert_hm12_to_rgb24(src, dest, width, height);
761
case V4L2_PIX_FMT_BGR24:
762
v4lconvert_hm12_to_bgr24(src, dest, width, height);
764
case V4L2_PIX_FMT_YUV420:
765
v4lconvert_hm12_to_yuv420(src, dest, width, height, 0);
767
case V4L2_PIX_FMT_YVU420:
768
v4lconvert_hm12_to_yuv420(src, dest, width, height, 1);
773
/* compressed bayer formats */
774
case V4L2_PIX_FMT_SPCA561:
775
case V4L2_PIX_FMT_SN9C10X:
776
case V4L2_PIX_FMT_PAC207:
777
case V4L2_PIX_FMT_MR97310A:
778
case V4L2_PIX_FMT_SN9C2028:
779
case V4L2_PIX_FMT_SQ905C:
780
case V4L2_PIX_FMT_STV0680: { /* Not compressed but needs some shuffling */
781
unsigned char *tmpbuf;
782
struct v4l2_format tmpfmt = *fmt;
784
tmpbuf = v4lconvert_alloc_buffer(width * height,
785
&data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
787
return v4lconvert_oom_error(data);
789
switch (src_pix_fmt) {
790
case V4L2_PIX_FMT_SPCA561:
791
v4lconvert_decode_spca561(src, tmpbuf, width, height);
792
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGBRG8;
794
case V4L2_PIX_FMT_SN9C10X:
795
v4lconvert_decode_sn9c10x(src, tmpbuf, width, height);
796
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
798
case V4L2_PIX_FMT_PAC207:
799
if (v4lconvert_decode_pac207(data, src, src_size, tmpbuf,
801
/* Corrupt frame, better get another one */
805
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
807
case V4L2_PIX_FMT_MR97310A:
808
if (v4lconvert_decode_mr97310a(data, src, src_size, tmpbuf,
810
/* Corrupt frame, better get another one */
814
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
816
case V4L2_PIX_FMT_SN9C2028:
817
v4lconvert_decode_sn9c2028(src, tmpbuf, width, height);
818
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
820
case V4L2_PIX_FMT_SQ905C:
821
v4lconvert_decode_sq905c(src, tmpbuf, width, height);
822
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
824
case V4L2_PIX_FMT_STV0680:
825
v4lconvert_decode_stv0680(src, tmpbuf, width, height);
826
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
829
/* Do processing on the tmp buffer, because doing it on bayer data is
830
cheaper, and bayer == rgb and our dest_fmt may be yuv */
831
tmpfmt.fmt.pix.bytesperline = width;
832
tmpfmt.fmt.pix.sizeimage = width * height;
833
v4lprocessing_processing(data->processing, tmpbuf, &tmpfmt);
834
/* Deliberate fall through to raw bayer fmt code! */
835
src_pix_fmt = tmpfmt.fmt.pix.pixelformat;
837
src_size = width * height;
841
/* Raw bayer formats */
842
case V4L2_PIX_FMT_SBGGR8:
843
case V4L2_PIX_FMT_SGBRG8:
844
case V4L2_PIX_FMT_SGRBG8:
845
case V4L2_PIX_FMT_SRGGB8:
846
switch (dest_pix_fmt) {
847
case V4L2_PIX_FMT_RGB24:
848
v4lconvert_bayer_to_rgb24(src, dest, width, height, src_pix_fmt);
850
case V4L2_PIX_FMT_BGR24:
851
v4lconvert_bayer_to_bgr24(src, dest, width, height, src_pix_fmt);
853
case V4L2_PIX_FMT_YUV420:
854
v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 0);
856
case V4L2_PIX_FMT_YVU420:
857
v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 1);
860
if (src_size < (width * height)) {
861
V4LCONVERT_ERR("short raw bayer data frame\n");
867
case V4L2_PIX_FMT_SE401: {
868
unsigned char *d = NULL;
870
switch (dest_pix_fmt) {
871
case V4L2_PIX_FMT_RGB24:
874
case V4L2_PIX_FMT_BGR24:
875
case V4L2_PIX_FMT_YUV420:
876
case V4L2_PIX_FMT_YVU420:
877
d = v4lconvert_alloc_buffer(width * height * 3,
878
&data->convert_pixfmt_buf,
879
&data->convert_pixfmt_buf_size);
881
return v4lconvert_oom_error(data);
883
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
884
v4lconvert_fixup_fmt(fmt);
888
result = v4lconvert_se401_to_rgb24(data, src, src_size, d,
890
switch (dest_pix_fmt) {
891
case V4L2_PIX_FMT_BGR24:
892
v4lconvert_swap_rgb(d, dest, width, height);
894
case V4L2_PIX_FMT_YUV420:
895
v4lconvert_rgb24_to_yuv420(d, dest, fmt, 0, 0);
897
case V4L2_PIX_FMT_YVU420:
898
v4lconvert_rgb24_to_yuv420(d, dest, fmt, 0, 1);
904
case V4L2_PIX_FMT_GREY:
905
switch (dest_pix_fmt) {
906
case V4L2_PIX_FMT_RGB24:
907
case V4L2_PIX_FMT_BGR24:
908
v4lconvert_grey_to_rgb24(src, dest, width, height);
910
case V4L2_PIX_FMT_YUV420:
911
case V4L2_PIX_FMT_YVU420:
912
v4lconvert_grey_to_yuv420(src, dest, fmt);
915
if (src_size < (width * height)) {
916
V4LCONVERT_ERR("short grey data frame\n");
922
case V4L2_PIX_FMT_Y10BPACK:
923
switch (dest_pix_fmt) {
924
case V4L2_PIX_FMT_RGB24:
925
case V4L2_PIX_FMT_BGR24:
926
result = v4lconvert_y10b_to_rgb24(data, src, dest,
929
case V4L2_PIX_FMT_YUV420:
930
case V4L2_PIX_FMT_YVU420:
931
result = v4lconvert_y10b_to_yuv420(data, src, dest,
935
if (result == 0 && src_size < (width * height * 10 / 8)) {
936
V4LCONVERT_ERR("short y10b data frame\n");
942
case V4L2_PIX_FMT_RGB565:
943
switch (dest_pix_fmt) {
944
case V4L2_PIX_FMT_RGB24:
945
v4lconvert_rgb565_to_rgb24(src, dest, width, height);
947
case V4L2_PIX_FMT_BGR24:
948
v4lconvert_rgb565_to_bgr24(src, dest, width, height);
950
case V4L2_PIX_FMT_YUV420:
951
v4lconvert_rgb565_to_yuv420(src, dest, fmt, 0);
953
case V4L2_PIX_FMT_YVU420:
954
v4lconvert_rgb565_to_yuv420(src, dest, fmt, 1);
957
if (src_size < (width * height * 2)) {
958
V4LCONVERT_ERR("short rgb565 data frame\n");
964
case V4L2_PIX_FMT_RGB24:
965
switch (dest_pix_fmt) {
966
case V4L2_PIX_FMT_RGB24:
967
memcpy(dest, src, width * height * 3);
969
case V4L2_PIX_FMT_BGR24:
970
v4lconvert_swap_rgb(src, dest, width, height);
972
case V4L2_PIX_FMT_YUV420:
973
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 0);
975
case V4L2_PIX_FMT_YVU420:
976
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 1);
979
if (src_size < (width * height * 3)) {
980
V4LCONVERT_ERR("short rgb24 data frame\n");
986
case V4L2_PIX_FMT_BGR24:
987
switch (dest_pix_fmt) {
988
case V4L2_PIX_FMT_RGB24:
989
v4lconvert_swap_rgb(src, dest, width, height);
991
case V4L2_PIX_FMT_BGR24:
992
memcpy(dest, src, width * height * 3);
994
case V4L2_PIX_FMT_YUV420:
995
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 0);
997
case V4L2_PIX_FMT_YVU420:
998
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 1);
1001
if (src_size < (width * height * 3)) {
1002
V4LCONVERT_ERR("short bgr24 data frame\n");
1008
case V4L2_PIX_FMT_YUV420:
1009
switch (dest_pix_fmt) {
1010
case V4L2_PIX_FMT_RGB24:
1011
v4lconvert_yuv420_to_rgb24(src, dest, width,
1014
case V4L2_PIX_FMT_BGR24:
1015
v4lconvert_yuv420_to_bgr24(src, dest, width,
1018
case V4L2_PIX_FMT_YUV420:
1019
memcpy(dest, src, width * height * 3 / 2);
1021
case V4L2_PIX_FMT_YVU420:
1022
v4lconvert_swap_uv(src, dest, fmt);
1025
if (src_size < (width * height * 3 / 2)) {
1026
V4LCONVERT_ERR("short yuv420 data frame\n");
1032
case V4L2_PIX_FMT_YVU420:
1033
switch (dest_pix_fmt) {
1034
case V4L2_PIX_FMT_RGB24:
1035
v4lconvert_yuv420_to_rgb24(src, dest, width,
1038
case V4L2_PIX_FMT_BGR24:
1039
v4lconvert_yuv420_to_bgr24(src, dest, width,
1042
case V4L2_PIX_FMT_YUV420:
1043
v4lconvert_swap_uv(src, dest, fmt);
1045
case V4L2_PIX_FMT_YVU420:
1046
memcpy(dest, src, width * height * 3 / 2);
1049
if (src_size < (width * height * 3 / 2)) {
1050
V4LCONVERT_ERR("short yvu420 data frame\n");
1056
case V4L2_PIX_FMT_YUYV:
1057
switch (dest_pix_fmt) {
1058
case V4L2_PIX_FMT_RGB24:
1059
v4lconvert_yuyv_to_rgb24(src, dest, width, height);
1061
case V4L2_PIX_FMT_BGR24:
1062
v4lconvert_yuyv_to_bgr24(src, dest, width, height);
1064
case V4L2_PIX_FMT_YUV420:
1065
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 0);
1067
case V4L2_PIX_FMT_YVU420:
1068
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 1);
1071
if (src_size < (width * height * 2)) {
1072
V4LCONVERT_ERR("short yuyv data frame\n");
1078
case V4L2_PIX_FMT_YVYU:
1079
switch (dest_pix_fmt) {
1080
case V4L2_PIX_FMT_RGB24:
1081
v4lconvert_yvyu_to_rgb24(src, dest, width, height);
1083
case V4L2_PIX_FMT_BGR24:
1084
v4lconvert_yvyu_to_bgr24(src, dest, width, height);
1086
case V4L2_PIX_FMT_YUV420:
1087
/* Note we use yuyv_to_yuv420 not v4lconvert_yvyu_to_yuv420,
1088
with the last argument reversed to make it have as we want */
1089
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 1);
1091
case V4L2_PIX_FMT_YVU420:
1092
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 0);
1095
if (src_size < (width * height * 2)) {
1096
V4LCONVERT_ERR("short yvyu data frame\n");
1102
case V4L2_PIX_FMT_UYVY:
1103
switch (dest_pix_fmt) {
1104
case V4L2_PIX_FMT_RGB24:
1105
v4lconvert_uyvy_to_rgb24(src, dest, width, height);
1107
case V4L2_PIX_FMT_BGR24:
1108
v4lconvert_uyvy_to_bgr24(src, dest, width, height);
1110
case V4L2_PIX_FMT_YUV420:
1111
v4lconvert_uyvy_to_yuv420(src, dest, width, height, 0);
1113
case V4L2_PIX_FMT_YVU420:
1114
v4lconvert_uyvy_to_yuv420(src, dest, width, height, 1);
1117
if (src_size < (width * height * 2)) {
1118
V4LCONVERT_ERR("short uyvy data frame\n");
1125
V4LCONVERT_ERR("Unknown src format in conversion\n");
1130
fmt->fmt.pix.pixelformat = dest_pix_fmt;
1131
v4lconvert_fixup_fmt(fmt);
1136
int v4lconvert_convert(struct v4lconvert_data *data,
1137
const struct v4l2_format *src_fmt, /* in */
1138
const struct v4l2_format *dest_fmt, /* in */
1139
unsigned char *src, int src_size, unsigned char *dest, int dest_size)
1141
int res, dest_needed, temp_needed, processing, convert = 0;
1142
int rotate90, vflip, hflip, crop;
1143
unsigned char *convert1_dest = dest;
1144
int convert1_dest_size = dest_size;
1145
unsigned char *convert2_src = src, *convert2_dest = dest;
1146
int convert2_dest_size = dest_size;
1147
unsigned char *rotate90_src = src, *rotate90_dest = dest;
1148
unsigned char *flip_src = src, *flip_dest = dest;
1149
unsigned char *crop_src = src;
1150
struct v4l2_format my_src_fmt = *src_fmt;
1151
struct v4l2_format my_dest_fmt = *dest_fmt;
1153
processing = v4lprocessing_pre_processing(data->processing);
1154
rotate90 = data->control_flags & V4LCONTROL_ROTATED_90_JPEG;
1155
hflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_HFLIP);
1156
vflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_VFLIP);
1157
crop = my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width ||
1158
my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height;
1160
if (/* If no conversion/processing is needed */
1161
(src_fmt->fmt.pix.pixelformat == dest_fmt->fmt.pix.pixelformat &&
1162
!processing && !rotate90 && !hflip && !vflip && !crop) ||
1163
/* or if we should do processing/rotating/flipping but the app tries to
1164
use the native cam format, we just return an unprocessed frame copy */
1165
!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) {
1166
int to_copy = MIN(dest_size, src_size);
1167
memcpy(dest, src, to_copy);
1171
/* When field is V4L2_FIELD_ALTERNATE, each buffer only contains half the
1173
if (my_src_fmt.fmt.pix.field == V4L2_FIELD_ALTERNATE) {
1174
my_src_fmt.fmt.pix.height /= 2;
1175
my_dest_fmt.fmt.pix.height /= 2;
1178
/* sanity check, is the dest buffer large enough? */
1179
switch (my_dest_fmt.fmt.pix.pixelformat) {
1180
case V4L2_PIX_FMT_RGB24:
1181
case V4L2_PIX_FMT_BGR24:
1182
dest_needed = my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3;
1183
temp_needed = my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
1185
case V4L2_PIX_FMT_YUV420:
1186
case V4L2_PIX_FMT_YVU420:
1188
my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3 / 2;
1190
my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3 / 2;
1193
V4LCONVERT_ERR("Unknown dest format in conversion\n");
1198
if (dest_size < dest_needed) {
1199
V4LCONVERT_ERR("destination buffer too small (%d < %d)\n",
1200
dest_size, dest_needed);
1206
/* Sometimes we need foo -> rgb -> bar as video processing (whitebalance,
1207
etc.) can only be done on rgb data */
1208
if (processing && v4lconvert_processing_needs_double_conversion(
1209
my_src_fmt.fmt.pix.pixelformat,
1210
my_dest_fmt.fmt.pix.pixelformat))
1212
else if (my_dest_fmt.fmt.pix.pixelformat !=
1213
my_src_fmt.fmt.pix.pixelformat ||
1214
/* Special case if we do not need to do conversion, but we
1215
are not doing any other step involving copying either,
1216
force going through convert_pixfmt to copy the data from
1218
(!rotate90 && !hflip && !vflip && !crop))
1221
/* convert_pixfmt (only if convert == 2) -> processing -> convert_pixfmt ->
1222
rotate -> flip -> crop, all steps are optional */
1224
convert1_dest = v4lconvert_alloc_buffer(
1225
my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3,
1226
&data->convert1_buf, &data->convert1_buf_size);
1228
return v4lconvert_oom_error(data);
1230
convert1_dest_size =
1231
my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
1232
convert2_src = convert1_dest;
1235
if (convert && (rotate90 || hflip || vflip || crop)) {
1236
convert2_dest = v4lconvert_alloc_buffer(temp_needed,
1237
&data->convert2_buf, &data->convert2_buf_size);
1239
return v4lconvert_oom_error(data);
1241
convert2_dest_size = temp_needed;
1242
rotate90_src = flip_src = crop_src = convert2_dest;
1245
if (rotate90 && (hflip || vflip || crop)) {
1246
rotate90_dest = v4lconvert_alloc_buffer(temp_needed,
1247
&data->rotate90_buf, &data->rotate90_buf_size);
1249
return v4lconvert_oom_error(data);
1251
flip_src = crop_src = rotate90_dest;
1254
if ((vflip || hflip) && crop) {
1255
flip_dest = v4lconvert_alloc_buffer(temp_needed, &data->flip_buf,
1256
&data->flip_buf_size);
1258
return v4lconvert_oom_error(data);
1260
crop_src = flip_dest;
1263
/* Done setting sources / dest and allocating intermediate buffers,
1264
real conversion / processing / ... starts here. */
1266
res = v4lconvert_convert_pixfmt(data, src, src_size,
1267
convert1_dest, convert1_dest_size,
1269
V4L2_PIX_FMT_RGB24);
1273
src_size = my_src_fmt.fmt.pix.sizeimage;
1277
v4lprocessing_processing(data->processing, convert2_src, &my_src_fmt);
1280
res = v4lconvert_convert_pixfmt(data, convert2_src, src_size,
1281
convert2_dest, convert2_dest_size,
1283
my_dest_fmt.fmt.pix.pixelformat);
1287
src_size = my_src_fmt.fmt.pix.sizeimage;
1289
/* We call processing here again in case the source format was not
1290
rgb, but the dest is. v4lprocessing checks it self it only actually
1291
does the processing once per frame. */
1293
v4lprocessing_processing(data->processing, convert2_dest, &my_src_fmt);
1297
v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt);
1300
v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, hflip, vflip);
1303
v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt);
1308
const char *v4lconvert_get_error_message(struct v4lconvert_data *data)
1310
return data->error_msg;
1313
static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
1314
unsigned int pixelformat, int index)
1317
struct v4l2_frmsizeenum frmsize = { .pixel_format = pixelformat };
1319
for (i = 0; ; i++) {
1321
if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize))
1324
/* We got a framesize, check we don't have the same one already */
1326
for (j = 0; j < data->no_framesizes; j++) {
1327
if (frmsize.type != data->framesizes[j].type)
1330
switch (frmsize.type) {
1331
case V4L2_FRMSIZE_TYPE_DISCRETE:
1332
if (!memcmp(&frmsize.discrete, &data->framesizes[j].discrete,
1333
sizeof(frmsize.discrete)))
1336
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1337
case V4L2_FRMSIZE_TYPE_STEPWISE:
1338
if (!memcmp(&frmsize.stepwise, &data->framesizes[j].stepwise,
1339
sizeof(frmsize.stepwise)))
1346
/* Add this framesize if it is not already in our list */
1348
if (data->no_framesizes == V4LCONVERT_MAX_FRAMESIZES) {
1349
fprintf(stderr, "libv4lconvert: warning more framesizes then I can handle!\n");
1352
data->framesizes[data->no_framesizes].type = frmsize.type;
1353
/* We use the pixel_format member to store a bitmask of all
1354
supported src_formats which can do this size */
1355
data->framesizes[data->no_framesizes].pixel_format = 1 << index;
1357
switch (frmsize.type) {
1358
case V4L2_FRMSIZE_TYPE_DISCRETE:
1359
data->framesizes[data->no_framesizes].discrete = frmsize.discrete;
1361
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1362
case V4L2_FRMSIZE_TYPE_STEPWISE:
1363
data->framesizes[data->no_framesizes].stepwise = frmsize.stepwise;
1366
data->no_framesizes++;
1368
data->framesizes[j].pixel_format |= 1 << index;
1373
int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
1374
struct v4l2_frmsizeenum *frmsize)
1376
if (!v4lconvert_supported_dst_format(frmsize->pixel_format)) {
1377
if (v4lconvert_supported_dst_fmt_only(data)) {
1381
return SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize);
1384
if (frmsize->index >= data->no_framesizes) {
1389
frmsize->type = data->framesizes[frmsize->index].type;
1390
switch (frmsize->type) {
1391
case V4L2_FRMSIZE_TYPE_DISCRETE:
1392
frmsize->discrete = data->framesizes[frmsize->index].discrete;
1393
/* Apply the same rounding algorithm as v4lconvert_try_format */
1394
frmsize->discrete.width &= ~7;
1395
frmsize->discrete.height &= ~1;
1397
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1398
case V4L2_FRMSIZE_TYPE_STEPWISE:
1399
frmsize->stepwise = data->framesizes[frmsize->index].stepwise;
1406
int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
1407
struct v4l2_frmivalenum *frmival)
1410
struct v4l2_format src_fmt, dest_fmt;
1412
if (!v4lconvert_supported_dst_format(frmival->pixel_format)) {
1413
if (v4lconvert_supported_dst_fmt_only(data)) {
1417
res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
1419
V4LCONVERT_ERR("%s\n", strerror(errno));
1423
/* Check which format we will be using to convert to frmival->pixel_format */
1424
memset(&dest_fmt, 0, sizeof(dest_fmt));
1425
dest_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1426
dest_fmt.fmt.pix.pixelformat = frmival->pixel_format;
1427
dest_fmt.fmt.pix.width = frmival->width;
1428
dest_fmt.fmt.pix.height = frmival->height;
1429
res = v4lconvert_try_format(data, &dest_fmt, &src_fmt);
1431
V4LCONVERT_ERR("trying format: %s\n", strerror(errno));
1435
/* Check the requested format is supported exactly as requested */
1436
if (dest_fmt.fmt.pix.pixelformat != frmival->pixel_format ||
1437
dest_fmt.fmt.pix.width != frmival->width ||
1438
dest_fmt.fmt.pix.height != frmival->height) {
1439
int frmival_pixformat = frmival->pixel_format;
1440
int dest_pixformat = dest_fmt.fmt.pix.pixelformat;
1442
V4LCONVERT_ERR("Could not find matching framesize for: %c%c%c%c %dx%d "
1443
"closest match: %c%c%c%c %dx%d\n",
1444
frmival_pixformat & 0xff,
1445
(frmival_pixformat >> 8) & 0xff,
1446
(frmival_pixformat >> 16) & 0xff,
1447
frmival_pixformat >> 24,
1448
frmival->width, frmival->height,
1449
dest_pixformat & 0xff,
1450
(dest_pixformat >> 8) & 0xff,
1451
(dest_pixformat >> 16) & 0xff,
1452
dest_pixformat >> 24,
1453
dest_fmt.fmt.pix.width , dest_fmt.fmt.pix.height);
1458
/* Enumerate the frameintervals of the source format we will be using */
1459
frmival->pixel_format = src_fmt.fmt.pix.pixelformat;
1460
frmival->width = src_fmt.fmt.pix.width;
1461
frmival->height = src_fmt.fmt.pix.height;
1462
res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
1464
int dest_pixfmt = dest_fmt.fmt.pix.pixelformat;
1465
int src_pixfmt = src_fmt.fmt.pix.pixelformat;
1467
V4LCONVERT_ERR("Could not enum frameival index: %d for: %c%c%c%c %dx%d "
1468
"using src: %c%c%c%c %dx%d, error: %s\n",
1471
(dest_pixfmt >> 8) & 0xff,
1472
(dest_pixfmt >> 16) & 0xff,
1474
dest_fmt.fmt.pix.width , dest_fmt.fmt.pix.height,
1476
(src_pixfmt >> 8) & 0xff,
1477
(src_pixfmt >> 16) & 0xff,
1479
src_fmt.fmt.pix.width, src_fmt.fmt.pix.height, strerror(errno));
1482
/* Restore the requested format in the frmival struct */
1483
frmival->pixel_format = dest_fmt.fmt.pix.pixelformat;
1484
frmival->width = dest_fmt.fmt.pix.width;
1485
frmival->height = dest_fmt.fmt.pix.height;
1490
int v4lconvert_vidioc_queryctrl(struct v4lconvert_data *data, void *arg)
1492
return v4lcontrol_vidioc_queryctrl(data->control, arg);
1495
int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data, void *arg)
1497
return v4lcontrol_vidioc_g_ctrl(data->control, arg);
1500
int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data, void *arg)
1502
return v4lcontrol_vidioc_s_ctrl(data->control, arg);
1505
int v4lconvert_get_fps(struct v4lconvert_data *data)
1510
void v4lconvert_set_fps(struct v4lconvert_data *data, int fps)