26
26
#include "libv4lconvert-priv.h"
27
27
#include "libv4lsyscall-priv.h"
29
#define MIN(a,b) (((a)<(b))?(a):(b))
29
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
31
31
/* Note for proper functioning of v4lconvert_enum_fmt the first entries in
32
supported_src_pixfmts must match with the entries in supported_dst_pixfmts */
32
supported_src_pixfmts must match with the entries in supported_dst_pixfmts */
33
33
#define SUPPORTED_DST_PIXFMTS \
34
{ V4L2_PIX_FMT_RGB24, 0 }, \
35
{ V4L2_PIX_FMT_BGR24, 0 }, \
36
{ V4L2_PIX_FMT_YUV420, 0 }, \
37
{ V4L2_PIX_FMT_YVU420, 0 }
34
{ V4L2_PIX_FMT_RGB24, 0 }, \
35
{ V4L2_PIX_FMT_BGR24, 0 }, \
36
{ V4L2_PIX_FMT_YUV420, 0 }, \
37
{ V4L2_PIX_FMT_YVU420, 0 }
39
39
static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
40
unsigned int pixelformat, int index);
40
unsigned int pixelformat, int index);
42
42
/* Note uncompressed formats must go first so that they are prefered by
43
43
v4lconvert_try_format for low resolutions */
44
44
static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
45
SUPPORTED_DST_PIXFMTS,
46
{ V4L2_PIX_FMT_YUYV, 0 },
47
{ V4L2_PIX_FMT_YVYU, 0 },
48
{ V4L2_PIX_FMT_UYVY, 0 },
49
{ V4L2_PIX_FMT_RGB565, 0 },
50
{ V4L2_PIX_FMT_SN9C20X_I420, V4LCONVERT_NEEDS_CONVERSION },
51
{ V4L2_PIX_FMT_SBGGR8, V4LCONVERT_NEEDS_CONVERSION },
52
{ V4L2_PIX_FMT_SGBRG8, V4LCONVERT_NEEDS_CONVERSION },
53
{ V4L2_PIX_FMT_SGRBG8, V4LCONVERT_NEEDS_CONVERSION },
54
{ V4L2_PIX_FMT_SRGGB8, V4LCONVERT_NEEDS_CONVERSION },
55
{ V4L2_PIX_FMT_STV0680, V4LCONVERT_NEEDS_CONVERSION },
56
{ V4L2_PIX_FMT_SPCA501, V4LCONVERT_NEEDS_CONVERSION },
57
{ V4L2_PIX_FMT_SPCA505, V4LCONVERT_NEEDS_CONVERSION },
58
{ V4L2_PIX_FMT_SPCA508, V4LCONVERT_NEEDS_CONVERSION },
59
{ V4L2_PIX_FMT_CPIA1, V4LCONVERT_NEEDS_CONVERSION },
60
{ V4L2_PIX_FMT_HM12, V4LCONVERT_NEEDS_CONVERSION },
61
{ V4L2_PIX_FMT_MJPEG, V4LCONVERT_COMPRESSED },
62
{ V4L2_PIX_FMT_JPEG, V4LCONVERT_COMPRESSED },
63
{ V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
64
{ V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
65
{ V4L2_PIX_FMT_SN9C2028, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
66
{ V4L2_PIX_FMT_PAC207, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
67
{ V4L2_PIX_FMT_MR97310A, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
68
{ V4L2_PIX_FMT_SQ905C, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
69
{ V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
70
{ V4L2_PIX_FMT_OV511, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
71
{ V4L2_PIX_FMT_OV518, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
45
SUPPORTED_DST_PIXFMTS,
46
{ V4L2_PIX_FMT_YUYV, 0 },
47
{ V4L2_PIX_FMT_YVYU, 0 },
48
{ V4L2_PIX_FMT_UYVY, 0 },
49
{ V4L2_PIX_FMT_RGB565, 0 },
50
{ V4L2_PIX_FMT_SN9C20X_I420, V4LCONVERT_NEEDS_CONVERSION },
51
{ V4L2_PIX_FMT_SBGGR8, V4LCONVERT_NEEDS_CONVERSION },
52
{ V4L2_PIX_FMT_SGBRG8, V4LCONVERT_NEEDS_CONVERSION },
53
{ V4L2_PIX_FMT_SGRBG8, V4LCONVERT_NEEDS_CONVERSION },
54
{ V4L2_PIX_FMT_SRGGB8, V4LCONVERT_NEEDS_CONVERSION },
55
{ V4L2_PIX_FMT_STV0680, V4LCONVERT_NEEDS_CONVERSION },
56
{ V4L2_PIX_FMT_SPCA501, V4LCONVERT_NEEDS_CONVERSION },
57
{ V4L2_PIX_FMT_SPCA505, V4LCONVERT_NEEDS_CONVERSION },
58
{ V4L2_PIX_FMT_SPCA508, V4LCONVERT_NEEDS_CONVERSION },
59
{ V4L2_PIX_FMT_CPIA1, V4LCONVERT_NEEDS_CONVERSION },
60
{ V4L2_PIX_FMT_HM12, V4LCONVERT_NEEDS_CONVERSION },
61
{ V4L2_PIX_FMT_MJPEG, V4LCONVERT_COMPRESSED },
62
{ V4L2_PIX_FMT_JPEG, V4LCONVERT_COMPRESSED },
63
{ V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
64
{ V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
65
{ V4L2_PIX_FMT_SN9C2028, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
66
{ V4L2_PIX_FMT_PAC207, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
67
{ V4L2_PIX_FMT_MR97310A, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
68
{ V4L2_PIX_FMT_SQ905C, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
69
{ V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
70
{ V4L2_PIX_FMT_OV511, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
71
{ V4L2_PIX_FMT_OV518, V4LCONVERT_COMPRESSED_AND_NEEDS_CONVERSION },
74
74
static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = {
78
78
/* List of well known resolutions which we can get by cropping somewhat larger
80
80
static const int v4lconvert_crop_res[][2] = {
81
/* low res VGA resolutions, can be made by software cropping SIF resolutions
82
for cam/drivers which do not support this in hardware */
85
/* Some CIF cams (with vv6410 sensor) have slightly larger then usual CIF
86
resolutions, make regular CIF resolutions available on these by sw crop */
81
/* low res VGA resolutions, can be made by software cropping SIF resolutions
82
for cam/drivers which do not support this in hardware */
85
/* Some CIF cams (with vv6410 sensor) have slightly larger then usual CIF
86
resolutions, make regular CIF resolutions available on these by sw crop */
91
91
struct v4lconvert_data *v4lconvert_create(int fd)
94
struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data));
95
struct v4l2_capability cap;
96
/* This keeps tracks of devices which have only formats for which apps
97
most likely will need conversion and we can thus safely add software
98
processing controls without a performance impact. */
99
int always_needs_conversion = 1;
102
fprintf(stderr, "libv4lconvert: error: out of memory!\n");
107
data->decompress_pid = -1;
109
/* Check supported formats */
111
struct v4l2_fmtdesc fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
115
if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, &fmt))
118
for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++)
119
if (fmt.pixelformat == supported_src_pixfmts[j].fmt) {
120
data->supported_src_formats |= 1 << j;
121
v4lconvert_get_framesizes(data, fmt.pixelformat, j);
122
if (!(supported_src_pixfmts[j].flags & V4LCONVERT_NEEDS_CONVERSION))
123
always_needs_conversion = 0;
127
if (j == ARRAY_SIZE(supported_src_pixfmts))
128
always_needs_conversion = 0;
131
data->no_formats = i;
133
/* Check if this cam has any special flags */
134
if (SYS_IOCTL(data->fd, VIDIOC_QUERYCAP, &cap) == 0) {
135
if (!strcmp((char *)cap.driver, "uvcvideo"))
136
data->flags |= V4LCONVERT_IS_UVC;
137
else if (!strcmp((char *)cap.driver, "sn9c20x"))
138
data->flags |= V4LCONVERT_IS_SN9C20X;
140
if ((cap.capabilities & 0xff) & ~V4L2_CAP_VIDEO_CAPTURE)
141
always_needs_conversion = 0;
144
data->control = v4lcontrol_create(fd, always_needs_conversion);
145
if (!data->control) {
149
data->control_flags = v4lcontrol_get_flags(data->control);
151
data->processing = v4lprocessing_create(fd, data->control);
152
if (!data->processing) {
153
v4lcontrol_destroy(data->control);
94
struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data));
95
struct v4l2_capability cap;
96
/* This keeps tracks of devices which have only formats for which apps
97
most likely will need conversion and we can thus safely add software
98
processing controls without a performance impact. */
99
int always_needs_conversion = 1;
102
fprintf(stderr, "libv4lconvert: error: out of memory!\n");
107
data->decompress_pid = -1;
109
/* Check supported formats */
111
struct v4l2_fmtdesc fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
115
if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, &fmt))
118
for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++)
119
if (fmt.pixelformat == supported_src_pixfmts[j].fmt) {
120
data->supported_src_formats |= 1 << j;
121
v4lconvert_get_framesizes(data, fmt.pixelformat, j);
122
if (!(supported_src_pixfmts[j].flags & V4LCONVERT_NEEDS_CONVERSION))
123
always_needs_conversion = 0;
127
if (j == ARRAY_SIZE(supported_src_pixfmts))
128
always_needs_conversion = 0;
131
data->no_formats = i;
133
/* Check if this cam has any special flags */
134
if (SYS_IOCTL(data->fd, VIDIOC_QUERYCAP, &cap) == 0) {
135
if (!strcmp((char *)cap.driver, "uvcvideo"))
136
data->flags |= V4LCONVERT_IS_UVC;
137
else if (!strcmp((char *)cap.driver, "sn9c20x"))
138
data->flags |= V4LCONVERT_IS_SN9C20X;
140
if ((cap.capabilities & 0xff) & ~V4L2_CAP_VIDEO_CAPTURE)
141
always_needs_conversion = 0;
144
data->control = v4lcontrol_create(fd, always_needs_conversion);
145
if (!data->control) {
149
data->control_flags = v4lcontrol_get_flags(data->control);
151
data->processing = v4lprocessing_create(fd, data->control);
152
if (!data->processing) {
153
v4lcontrol_destroy(data->control);
161
161
void v4lconvert_destroy(struct v4lconvert_data *data)
163
v4lprocessing_destroy(data->processing);
164
v4lcontrol_destroy(data->control);
166
unsigned char *comps[3] = { NULL, NULL, NULL };
167
tinyjpeg_set_components(data->jdec, comps, 3);
168
tinyjpeg_free(data->jdec);
170
v4lconvert_helper_cleanup(data);
171
free(data->convert1_buf);
172
free(data->convert2_buf);
173
free(data->rotate90_buf);
174
free(data->flip_buf);
175
free(data->convert_pixfmt_buf);
176
free(data->previous_frame);
163
v4lprocessing_destroy(data->processing);
164
v4lcontrol_destroy(data->control);
166
unsigned char *comps[3] = { NULL, NULL, NULL };
168
tinyjpeg_set_components(data->jdec, comps, 3);
169
tinyjpeg_free(data->jdec);
171
v4lconvert_helper_cleanup(data);
172
free(data->convert1_buf);
173
free(data->convert2_buf);
174
free(data->rotate90_buf);
175
free(data->flip_buf);
176
free(data->convert_pixfmt_buf);
177
free(data->previous_frame);
180
181
int v4lconvert_supported_dst_format(unsigned int pixelformat)
184
for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
185
if (supported_dst_pixfmts[i].fmt == pixelformat)
188
return i != ARRAY_SIZE(supported_dst_pixfmts);
185
for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
186
if (supported_dst_pixfmts[i].fmt == pixelformat)
189
return i != ARRAY_SIZE(supported_dst_pixfmts);
191
192
int v4lconvert_supported_dst_fmt_only(struct v4lconvert_data *data)
193
return v4lcontrol_needs_conversion(data->control) &&
194
data->supported_src_formats;
194
return v4lcontrol_needs_conversion(data->control) &&
195
data->supported_src_formats;
197
198
/* See libv4lconvert.h for description of in / out parameters */
198
199
int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
200
int i, no_faked_fmts = 0;
201
unsigned int faked_fmts[ARRAY_SIZE(supported_dst_pixfmts)];
203
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
204
(!v4lconvert_supported_dst_fmt_only(data) &&
205
fmt->index < data->no_formats))
206
return SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, fmt);
208
for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
209
if (v4lconvert_supported_dst_fmt_only(data) ||
210
!(data->supported_src_formats & (1 << i))) {
211
faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i].fmt;
215
if (!v4lconvert_supported_dst_fmt_only(data))
216
i = fmt->index - data->no_formats;
220
if (i >= no_faked_fmts) {
225
fmt->flags = V4L2_FMT_FLAG_EMULATED;
226
fmt->pixelformat = faked_fmts[i];
227
fmt->description[0] = faked_fmts[i] & 0xff;
228
fmt->description[1] = (faked_fmts[i] >> 8) & 0xff;
229
fmt->description[2] = (faked_fmts[i] >> 16) & 0xff;
230
fmt->description[3] = faked_fmts[i] >> 24;
231
fmt->description[4] = '\0';
232
memset(fmt->reserved, 0, 4);
201
int i, no_faked_fmts = 0;
202
unsigned int faked_fmts[ARRAY_SIZE(supported_dst_pixfmts)];
204
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
205
(!v4lconvert_supported_dst_fmt_only(data) &&
206
fmt->index < data->no_formats))
207
return SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, fmt);
209
for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
210
if (v4lconvert_supported_dst_fmt_only(data) ||
211
!(data->supported_src_formats & (1 << i))) {
212
faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i].fmt;
216
if (!v4lconvert_supported_dst_fmt_only(data))
217
i = fmt->index - data->no_formats;
221
if (i >= no_faked_fmts) {
226
fmt->flags = V4L2_FMT_FLAG_EMULATED;
227
fmt->pixelformat = faked_fmts[i];
228
fmt->description[0] = faked_fmts[i] & 0xff;
229
fmt->description[1] = (faked_fmts[i] >> 8) & 0xff;
230
fmt->description[2] = (faked_fmts[i] >> 16) & 0xff;
231
fmt->description[3] = faked_fmts[i] >> 24;
232
fmt->description[4] = '\0';
233
memset(fmt->reserved, 0, 4);
237
238
/* Find out what format to use based on the (cached) results of enum
239
240
currently is intended for use with UVC cams only. This is esp.
240
241
important for UVC based cams as doing try_fmt there actually causes I/O */
241
242
static int v4lconvert_do_try_format_uvc(struct v4lconvert_data *data,
242
struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
243
struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
245
unsigned int closest_fmt_size_diff = -1;
246
int best_framesize = 0;/* Just use the first format if no small enough one */
249
for (i = 0; i < data->no_framesizes; i++) {
250
if (data->framesizes[i].discrete.width <= dest_fmt->fmt.pix.width &&
251
data->framesizes[i].discrete.height <= dest_fmt->fmt.pix.height) {
252
int size_x_diff = dest_fmt->fmt.pix.width -
253
data->framesizes[i].discrete.width;
254
int size_y_diff = dest_fmt->fmt.pix.height -
255
data->framesizes[i].discrete.height;
256
unsigned int size_diff = size_x_diff * size_x_diff +
257
size_y_diff * size_y_diff;
259
if (size_diff < closest_fmt_size_diff) {
260
closest_fmt_size_diff = size_diff;
266
for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
267
/* is this format supported? */
268
if (!(data->framesizes[best_framesize].pixel_format & (1 << i)))
272
supported_src_pixfmts[i].fmt == dest_fmt->fmt.pix.pixelformat ||
273
((data->framesizes[best_framesize].discrete.width > 180 ||
274
data->framesizes[best_framesize].discrete.height > 148) &&
275
(supported_src_pixfmts[i].flags & V4LCONVERT_COMPRESSED)))
276
best_format = supported_src_pixfmts[i].fmt;
279
dest_fmt->fmt.pix.width = data->framesizes[best_framesize].discrete.width;
280
dest_fmt->fmt.pix.height = data->framesizes[best_framesize].discrete.height;
281
dest_fmt->fmt.pix.field = V4L2_FIELD_NONE; /* UVC has no fields */
282
/* Not pretty, the pwc driver doesn't fill these in try_fmt either though,
283
so we should be able to get away with this. */
284
dest_fmt->fmt.pix.bytesperline = 0;
285
dest_fmt->fmt.pix.sizeimage = 0;
286
dest_fmt->fmt.pix.colorspace = 0;
287
dest_fmt->fmt.pix.priv = 0;
289
*src_fmt = *dest_fmt;
290
src_fmt->fmt.pix.pixelformat = best_format;
246
unsigned int closest_fmt_size_diff = -1;
247
int best_framesize = 0;/* Just use the first format if no small enough one */
250
for (i = 0; i < data->no_framesizes; i++) {
251
if (data->framesizes[i].discrete.width <= dest_fmt->fmt.pix.width &&
252
data->framesizes[i].discrete.height <= dest_fmt->fmt.pix.height) {
253
int size_x_diff = dest_fmt->fmt.pix.width -
254
data->framesizes[i].discrete.width;
255
int size_y_diff = dest_fmt->fmt.pix.height -
256
data->framesizes[i].discrete.height;
257
unsigned int size_diff = size_x_diff * size_x_diff +
258
size_y_diff * size_y_diff;
260
if (size_diff < closest_fmt_size_diff) {
261
closest_fmt_size_diff = size_diff;
267
for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
268
/* is this format supported? */
269
if (!(data->framesizes[best_framesize].pixel_format & (1 << i)))
273
supported_src_pixfmts[i].fmt == dest_fmt->fmt.pix.pixelformat ||
274
((data->framesizes[best_framesize].discrete.width > 180 ||
275
data->framesizes[best_framesize].discrete.height > 148) &&
276
(supported_src_pixfmts[i].flags & V4LCONVERT_COMPRESSED)))
277
best_format = supported_src_pixfmts[i].fmt;
280
dest_fmt->fmt.pix.width = data->framesizes[best_framesize].discrete.width;
281
dest_fmt->fmt.pix.height = data->framesizes[best_framesize].discrete.height;
282
dest_fmt->fmt.pix.field = V4L2_FIELD_NONE; /* UVC has no fields */
283
/* Not pretty, the pwc driver doesn't fill these in try_fmt either though,
284
so we should be able to get away with this. */
285
dest_fmt->fmt.pix.bytesperline = 0;
286
dest_fmt->fmt.pix.sizeimage = 0;
287
dest_fmt->fmt.pix.colorspace = 0;
288
dest_fmt->fmt.pix.priv = 0;
290
*src_fmt = *dest_fmt;
291
src_fmt->fmt.pix.pixelformat = best_format;
295
296
static int v4lconvert_do_try_format(struct v4lconvert_data *data,
296
struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
297
struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
299
unsigned int closest_fmt_size_diff = -1;
300
unsigned int desired_pixfmt = dest_fmt->fmt.pix.pixelformat;
301
struct v4l2_format try_fmt, closest_fmt = { .type = 0 };
303
if (data->flags & V4LCONVERT_IS_UVC)
304
return v4lconvert_do_try_format_uvc(data, dest_fmt, src_fmt);
306
for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
307
/* is this format supported? */
308
if (!(data->supported_src_formats & (1 << i)))
312
try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt;
314
if (!SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, &try_fmt))
316
if (try_fmt.fmt.pix.pixelformat == supported_src_pixfmts[i].fmt) {
317
int size_x_diff = abs((int)try_fmt.fmt.pix.width -
318
(int)dest_fmt->fmt.pix.width);
319
int size_y_diff = abs((int)try_fmt.fmt.pix.height -
320
(int)dest_fmt->fmt.pix.height);
321
unsigned int size_diff = size_x_diff * size_x_diff +
322
size_y_diff * size_y_diff;
323
if (size_diff < closest_fmt_size_diff ||
324
(size_diff == closest_fmt_size_diff &&
325
(supported_src_pixfmts[i].fmt == desired_pixfmt ||
326
((try_fmt.fmt.pix.width > 180 || try_fmt.fmt.pix.height > 148) &&
327
(supported_src_pixfmts[i].flags & V4LCONVERT_COMPRESSED))))) {
328
closest_fmt_size_diff = size_diff;
329
closest_fmt = try_fmt;
300
unsigned int closest_fmt_size_diff = -1;
301
unsigned int desired_pixfmt = dest_fmt->fmt.pix.pixelformat;
302
struct v4l2_format try_fmt, closest_fmt = { .type = 0 };
304
if (data->flags & V4LCONVERT_IS_UVC)
305
return v4lconvert_do_try_format_uvc(data, dest_fmt, src_fmt);
307
for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
308
/* is this format supported? */
309
if (!(data->supported_src_formats & (1 << i)))
313
try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt;
315
if (!SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, &try_fmt)) {
316
if (try_fmt.fmt.pix.pixelformat == supported_src_pixfmts[i].fmt) {
317
int size_x_diff = abs((int)try_fmt.fmt.pix.width -
318
(int)dest_fmt->fmt.pix.width);
319
int size_y_diff = abs((int)try_fmt.fmt.pix.height -
320
(int)dest_fmt->fmt.pix.height);
321
unsigned int size_diff = size_x_diff * size_x_diff +
322
size_y_diff * size_y_diff;
324
if (size_diff < closest_fmt_size_diff ||
325
(size_diff == closest_fmt_size_diff &&
326
(supported_src_pixfmts[i].fmt == desired_pixfmt ||
327
((try_fmt.fmt.pix.width > 180 || try_fmt.fmt.pix.height > 148) &&
328
(supported_src_pixfmts[i].flags & V4LCONVERT_COMPRESSED))))) {
329
closest_fmt_size_diff = size_diff;
330
closest_fmt = try_fmt;
335
if (closest_fmt.type == 0)
338
*dest_fmt = closest_fmt;
339
if (closest_fmt.fmt.pix.pixelformat != desired_pixfmt)
340
dest_fmt->fmt.pix.pixelformat = desired_pixfmt;
341
*src_fmt = closest_fmt;
336
if (closest_fmt.type == 0)
339
*dest_fmt = closest_fmt;
340
if (closest_fmt.fmt.pix.pixelformat != desired_pixfmt)
341
dest_fmt->fmt.pix.pixelformat = desired_pixfmt;
342
*src_fmt = closest_fmt;
346
347
void v4lconvert_fixup_fmt(struct v4l2_format *fmt)
348
switch (fmt->fmt.pix.pixelformat) {
349
case V4L2_PIX_FMT_RGB24:
350
case V4L2_PIX_FMT_BGR24:
351
fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * 3;
352
fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3;
354
case V4L2_PIX_FMT_YUV420:
355
case V4L2_PIX_FMT_YVU420:
356
fmt->fmt.pix.bytesperline = fmt->fmt.pix.width;
357
fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3 / 2;
349
switch (fmt->fmt.pix.pixelformat) {
350
case V4L2_PIX_FMT_RGB24:
351
case V4L2_PIX_FMT_BGR24:
352
fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * 3;
353
fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3;
355
case V4L2_PIX_FMT_YUV420:
356
case V4L2_PIX_FMT_YVU420:
357
fmt->fmt.pix.bytesperline = fmt->fmt.pix.width;
358
fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height * 3 / 2;
362
363
/* See libv4lconvert.h for description of in / out parameters */
363
364
int v4lconvert_try_format(struct v4lconvert_data *data,
364
struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
365
struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
367
unsigned int desired_width = dest_fmt->fmt.pix.width;
368
unsigned int desired_height = dest_fmt->fmt.pix.height;
369
struct v4l2_format try_src, try_dest, try2_src, try2_dest;
371
if (dest_fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
372
v4lconvert_supported_dst_fmt_only(data) &&
373
!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat))
374
dest_fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
376
try_dest = *dest_fmt;
378
/* Can we do conversion to the requested format & type? */
379
if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) ||
380
dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
381
v4lconvert_do_try_format(data, &try_dest, &try_src)) {
382
result = SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, dest_fmt);
384
*src_fmt = *dest_fmt;
388
/* In case of a non exact resolution match, try again with a slightly larger
389
resolution as some weird devices are not able to crop of the number of
390
extra (border) pixels most sensors have compared to standard resolutions,
391
which we will then just crop of in software */
392
if (try_dest.fmt.pix.width != desired_width ||
393
try_dest.fmt.pix.height != desired_height) {
394
try2_dest = *dest_fmt;
395
try2_dest.fmt.pix.width = desired_width + 7;
396
try2_dest.fmt.pix.height = desired_height + 1;
397
result = v4lconvert_do_try_format(data, &try2_dest, &try2_src);
399
try2_dest.fmt.pix.width >= desired_width &&
400
try2_dest.fmt.pix.width <= desired_width + 7 &&
401
try2_dest.fmt.pix.height >= desired_height &&
402
try2_dest.fmt.pix.height <= desired_height + 1) {
404
try2_dest.fmt.pix.width = desired_width;
405
try2_dest.fmt.pix.height = desired_height;
406
try_dest = try2_dest;
411
/* In case of a non exact resolution match, see if this is a well known
412
resolution some apps are hardcoded too and try to give the app what it
413
asked for by cropping a slightly larger resolution or adding a small
414
black border to a slightly smaller resolution */
415
if (try_dest.fmt.pix.width != desired_width ||
416
try_dest.fmt.pix.height != desired_height) {
417
for (i = 0; i < ARRAY_SIZE(v4lconvert_crop_res); i++) {
418
if (v4lconvert_crop_res[i][0] == desired_width &&
419
v4lconvert_crop_res[i][1] == desired_height) {
420
try2_dest = *dest_fmt;
422
/* Note these are chosen so that cropping to vga res just works for
423
vv6410 sensor cams, which have 356x292 and 180x148 */
424
try2_dest.fmt.pix.width = desired_width * 113 / 100;
425
try2_dest.fmt.pix.height = desired_height * 124 / 100;
426
result = v4lconvert_do_try_format(data, &try2_dest, &try2_src);
428
(/* Add a small black border of max 16 pixels */
429
(try2_dest.fmt.pix.width >= desired_width - 16 &&
430
try2_dest.fmt.pix.width <= desired_width &&
431
try2_dest.fmt.pix.height >= desired_height - 16 &&
432
try2_dest.fmt.pix.height <= desired_height) ||
433
/* Standard cropping to max 80% of actual width / height */
434
(try2_dest.fmt.pix.width >= desired_width &&
435
try2_dest.fmt.pix.width <= desired_width * 5 / 4 &&
436
try2_dest.fmt.pix.height >= desired_height &&
437
try2_dest.fmt.pix.height <= desired_height * 5 / 4) ||
438
/* Downscale 2x + cropping to max 80% of actual width / height */
439
(try2_dest.fmt.pix.width >= desired_width * 2 &&
440
try2_dest.fmt.pix.width <= desired_width * 5 / 2 &&
441
try2_dest.fmt.pix.height >= desired_height * 2 &&
442
try2_dest.fmt.pix.height <= desired_height * 5 / 2))) {
444
try2_dest.fmt.pix.width = desired_width;
445
try2_dest.fmt.pix.height = desired_height;
446
try_dest = try2_dest;
454
/* Some applications / libs (*cough* gstreamer *cough*) will not work
455
correctly with planar YUV formats when the width is not a multiple of 8
456
or the height is not a multiple of 2. With RGB formats these apps require
457
the width to be a multiple of 4. We apply the same rounding to all
458
formats to not end up with 2 close but different resolutions. */
459
try_dest.fmt.pix.width &= ~7;
460
try_dest.fmt.pix.height &= ~1;
462
/* Are we converting / cropping ? */
463
if(try_src.fmt.pix.width != try_dest.fmt.pix.width ||
464
try_src.fmt.pix.height != try_dest.fmt.pix.height ||
465
try_src.fmt.pix.pixelformat != try_dest.fmt.pix.pixelformat)
466
v4lconvert_fixup_fmt(&try_dest);
468
*dest_fmt = try_dest;
368
unsigned int desired_width = dest_fmt->fmt.pix.width;
369
unsigned int desired_height = dest_fmt->fmt.pix.height;
370
struct v4l2_format try_src, try_dest, try2_src, try2_dest;
372
if (dest_fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
373
v4lconvert_supported_dst_fmt_only(data) &&
374
!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat))
375
dest_fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
377
try_dest = *dest_fmt;
379
/* Can we do conversion to the requested format & type? */
380
if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) ||
381
dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
382
v4lconvert_do_try_format(data, &try_dest, &try_src)) {
383
result = SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, dest_fmt);
385
*src_fmt = *dest_fmt;
389
/* In case of a non exact resolution match, try again with a slightly larger
390
resolution as some weird devices are not able to crop of the number of
391
extra (border) pixels most sensors have compared to standard resolutions,
392
which we will then just crop of in software */
393
if (try_dest.fmt.pix.width != desired_width ||
394
try_dest.fmt.pix.height != desired_height) {
395
try2_dest = *dest_fmt;
396
try2_dest.fmt.pix.width = desired_width + 7;
397
try2_dest.fmt.pix.height = desired_height + 1;
398
result = v4lconvert_do_try_format(data, &try2_dest, &try2_src);
400
try2_dest.fmt.pix.width >= desired_width &&
401
try2_dest.fmt.pix.width <= desired_width + 7 &&
402
try2_dest.fmt.pix.height >= desired_height &&
403
try2_dest.fmt.pix.height <= desired_height + 1) {
405
try2_dest.fmt.pix.width = desired_width;
406
try2_dest.fmt.pix.height = desired_height;
407
try_dest = try2_dest;
412
/* In case of a non exact resolution match, see if this is a well known
413
resolution some apps are hardcoded too and try to give the app what it
414
asked for by cropping a slightly larger resolution or adding a small
415
black border to a slightly smaller resolution */
416
if (try_dest.fmt.pix.width != desired_width ||
417
try_dest.fmt.pix.height != desired_height) {
418
for (i = 0; i < ARRAY_SIZE(v4lconvert_crop_res); i++) {
419
if (v4lconvert_crop_res[i][0] == desired_width &&
420
v4lconvert_crop_res[i][1] == desired_height) {
421
try2_dest = *dest_fmt;
423
/* Note these are chosen so that cropping to vga res just works for
424
vv6410 sensor cams, which have 356x292 and 180x148 */
425
try2_dest.fmt.pix.width = desired_width * 113 / 100;
426
try2_dest.fmt.pix.height = desired_height * 124 / 100;
427
result = v4lconvert_do_try_format(data, &try2_dest, &try2_src);
429
(/* Add a small black border of max 16 pixels */
430
(try2_dest.fmt.pix.width >= desired_width - 16 &&
431
try2_dest.fmt.pix.width <= desired_width &&
432
try2_dest.fmt.pix.height >= desired_height - 16 &&
433
try2_dest.fmt.pix.height <= desired_height) ||
434
/* Standard cropping to max 80% of actual width / height */
435
(try2_dest.fmt.pix.width >= desired_width &&
436
try2_dest.fmt.pix.width <= desired_width * 5 / 4 &&
437
try2_dest.fmt.pix.height >= desired_height &&
438
try2_dest.fmt.pix.height <= desired_height * 5 / 4) ||
439
/* Downscale 2x + cropping to max 80% of actual width / height */
440
(try2_dest.fmt.pix.width >= desired_width * 2 &&
441
try2_dest.fmt.pix.width <= desired_width * 5 / 2 &&
442
try2_dest.fmt.pix.height >= desired_height * 2 &&
443
try2_dest.fmt.pix.height <= desired_height * 5 / 2))) {
445
try2_dest.fmt.pix.width = desired_width;
446
try2_dest.fmt.pix.height = desired_height;
447
try_dest = try2_dest;
455
/* Some applications / libs (*cough* gstreamer *cough*) will not work
456
correctly with planar YUV formats when the width is not a multiple of 8
457
or the height is not a multiple of 2. With RGB formats these apps require
458
the width to be a multiple of 4. We apply the same rounding to all
459
formats to not end up with 2 close but different resolutions. */
460
try_dest.fmt.pix.width &= ~7;
461
try_dest.fmt.pix.height &= ~1;
463
/* Are we converting / cropping ? */
464
if (try_src.fmt.pix.width != try_dest.fmt.pix.width ||
465
try_src.fmt.pix.height != try_dest.fmt.pix.height ||
466
try_src.fmt.pix.pixelformat != try_dest.fmt.pix.pixelformat)
467
v4lconvert_fixup_fmt(&try_dest);
469
*dest_fmt = try_dest;
475
476
/* Is conversion necessary ? */
476
477
int v4lconvert_needs_conversion(struct v4lconvert_data *data,
477
const struct v4l2_format *src_fmt, /* in */
478
const struct v4l2_format *dest_fmt) /* in */
478
const struct v4l2_format *src_fmt, /* in */
479
const struct v4l2_format *dest_fmt) /* in */
480
if (src_fmt->fmt.pix.width != dest_fmt->fmt.pix.width ||
481
src_fmt->fmt.pix.height != dest_fmt->fmt.pix.height ||
482
src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat ||
483
(v4lcontrol_needs_conversion(data->control) &&
484
v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)))
481
if (src_fmt->fmt.pix.width != dest_fmt->fmt.pix.width ||
482
src_fmt->fmt.pix.height != dest_fmt->fmt.pix.height ||
483
src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat ||
484
(v4lcontrol_needs_conversion(data->control) &&
485
v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)))
490
491
static int v4lconvert_processing_needs_double_conversion(
491
unsigned int src_pix_fmt, unsigned int dest_pix_fmt)
492
unsigned int src_pix_fmt, unsigned int dest_pix_fmt)
493
switch (src_pix_fmt) {
494
case V4L2_PIX_FMT_RGB24:
495
case V4L2_PIX_FMT_BGR24:
496
case V4L2_PIX_FMT_SPCA561:
497
case V4L2_PIX_FMT_SN9C10X:
498
case V4L2_PIX_FMT_PAC207:
499
case V4L2_PIX_FMT_MR97310A:
500
case V4L2_PIX_FMT_SN9C2028:
501
case V4L2_PIX_FMT_SQ905C:
502
case V4L2_PIX_FMT_SBGGR8:
503
case V4L2_PIX_FMT_SGBRG8:
504
case V4L2_PIX_FMT_SGRBG8:
505
case V4L2_PIX_FMT_SRGGB8:
506
case V4L2_PIX_FMT_STV0680:
509
switch (dest_pix_fmt) {
510
case V4L2_PIX_FMT_RGB24:
511
case V4L2_PIX_FMT_BGR24:
494
switch (src_pix_fmt) {
495
case V4L2_PIX_FMT_RGB24:
496
case V4L2_PIX_FMT_BGR24:
497
case V4L2_PIX_FMT_SPCA561:
498
case V4L2_PIX_FMT_SN9C10X:
499
case V4L2_PIX_FMT_PAC207:
500
case V4L2_PIX_FMT_MR97310A:
501
case V4L2_PIX_FMT_SN9C2028:
502
case V4L2_PIX_FMT_SQ905C:
503
case V4L2_PIX_FMT_SBGGR8:
504
case V4L2_PIX_FMT_SGBRG8:
505
case V4L2_PIX_FMT_SGRBG8:
506
case V4L2_PIX_FMT_SRGGB8:
507
case V4L2_PIX_FMT_STV0680:
510
switch (dest_pix_fmt) {
511
case V4L2_PIX_FMT_RGB24:
512
case V4L2_PIX_FMT_BGR24:
518
519
unsigned char *v4lconvert_alloc_buffer(int needed,
519
unsigned char **buf, int *buf_size)
520
unsigned char **buf, int *buf_size)
521
if (*buf_size < needed) {
523
*buf = malloc(needed);
522
if (*buf_size < needed) {
524
*buf = malloc(needed);
533
534
static int v4lconvert_oom_error(struct v4lconvert_data *data)
535
V4LCONVERT_ERR("could not allocate memory\n");
536
V4LCONVERT_ERR("could not allocate memory\n");
540
541
static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
541
unsigned char *src, int src_size, unsigned char *dest, int dest_size,
542
struct v4l2_format *fmt, unsigned int dest_pix_fmt)
542
unsigned char *src, int src_size, unsigned char *dest, int dest_size,
543
struct v4l2_format *fmt, unsigned int dest_pix_fmt)
544
unsigned int header_width, header_height;
545
int result = 0, jpeg_flags = TINYJPEG_FLAGS_MJPEG_TABLE;
546
unsigned char *components[3];
547
unsigned int src_pix_fmt = fmt->fmt.pix.pixelformat;
548
unsigned int width = fmt->fmt.pix.width;
549
unsigned int height = fmt->fmt.pix.height;
551
switch (src_pix_fmt) {
552
case V4L2_PIX_FMT_PJPG:
553
jpeg_flags |= TINYJPEG_FLAGS_PIXART_JPEG;
555
case V4L2_PIX_FMT_MJPEG:
556
case V4L2_PIX_FMT_JPEG:
558
data->jdec = tinyjpeg_init();
560
return v4lconvert_oom_error(data);
562
tinyjpeg_set_flags(data->jdec, jpeg_flags);
563
if (tinyjpeg_parse_header(data->jdec, src, src_size)) {
564
V4LCONVERT_ERR("parsing JPEG header: %s",
565
tinyjpeg_get_errorstring(data->jdec));
569
tinyjpeg_get_size(data->jdec, &header_width, &header_height);
571
if (header_width != width || header_height != height) {
572
/* Check for (pixart) rotated JPEG */
573
if (header_width == height && header_height == width) {
574
if (!(data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) {
575
V4LCONVERT_ERR("JPEG needs 90° rotation, please report "
576
"this to <hdegoede@redhat.com>\n");
580
fmt->fmt.pix.width = header_width;
581
fmt->fmt.pix.height = header_height;
583
V4LCONVERT_ERR("unexpected width / height in JPEG header"
584
"expected: %ux%u, header: %ux%u\n", width, height,
585
header_width, header_height);
589
} else if ((data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) {
590
fprintf(stderr, "libv4lconvert: expected 90° rotated JPEG, but got "
591
"normal JPEG, please report this to <hdegoede@redhat.com>\n");
592
V4LCONVERT_ERR("expected 90° rotated JPEG, but got normal JPEG\n");
594
data->control_flags &= ~V4LCONTROL_ROTATED_90_JPEG;
598
components[0] = dest;
600
switch (dest_pix_fmt) {
601
case V4L2_PIX_FMT_RGB24:
602
tinyjpeg_set_components(data->jdec, components, 1);
603
result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_RGB24);
605
case V4L2_PIX_FMT_BGR24:
606
tinyjpeg_set_components(data->jdec, components, 1);
607
result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_BGR24);
609
case V4L2_PIX_FMT_YUV420:
610
components[1] = components[0] + width * height;
611
components[2] = components[1] + width * height / 4;
612
tinyjpeg_set_components(data->jdec, components, 3);
613
result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_YUV420P);
615
case V4L2_PIX_FMT_YVU420:
616
components[2] = components[0] + width * height;
617
components[1] = components[2] + width * height / 4;
618
tinyjpeg_set_components(data->jdec, components, 3);
619
result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_YUV420P);
624
/* Pixart webcam's seem to regulary generate corrupt frames, which
625
are best thrown away to avoid flashes in the video stream. Tell
626
the upper layer this is an intermediate fault and it should try
627
again with a new buffer by setting errno to EAGAIN */
628
if (src_pix_fmt == V4L2_PIX_FMT_PJPG ||
629
data->flags & V4LCONVERT_IS_SN9C20X) {
630
V4LCONVERT_ERR("decompressing JPEG: %s",
631
tinyjpeg_get_errorstring(data->jdec));
635
/* If the JPEG header checked out ok and we get an error during actual
636
decompression, log the error, but don't return an errorcode to the
637
application, so that the user gets what we managed to decompress */
638
fprintf(stderr, "libv4lconvert: Error decompressing JPEG: %s",
639
tinyjpeg_get_errorstring(data->jdec));
644
/* Custom cam specific YUV formats */
645
case V4L2_PIX_FMT_SPCA501:
646
case V4L2_PIX_FMT_SPCA505:
647
case V4L2_PIX_FMT_SPCA508:
648
case V4L2_PIX_FMT_SN9C20X_I420:
649
case V4L2_PIX_FMT_CPIA1:
650
case V4L2_PIX_FMT_OV511:
651
case V4L2_PIX_FMT_OV518:
657
if (dest_pix_fmt != V4L2_PIX_FMT_YUV420 &&
658
dest_pix_fmt != V4L2_PIX_FMT_YVU420) {
659
d = v4lconvert_alloc_buffer(width * height * 3 / 2,
660
&data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
662
return v4lconvert_oom_error(data);
663
d_size = width * height * 3 / 2;
669
if (dest_pix_fmt == V4L2_PIX_FMT_YVU420)
672
switch (src_pix_fmt) {
545
unsigned int header_width, header_height;
546
int result = 0, jpeg_flags = TINYJPEG_FLAGS_MJPEG_TABLE;
547
unsigned char *components[3];
548
unsigned int src_pix_fmt = fmt->fmt.pix.pixelformat;
549
unsigned int width = fmt->fmt.pix.width;
550
unsigned int height = fmt->fmt.pix.height;
552
switch (src_pix_fmt) {
553
case V4L2_PIX_FMT_PJPG:
554
jpeg_flags |= TINYJPEG_FLAGS_PIXART_JPEG;
556
case V4L2_PIX_FMT_MJPEG:
557
case V4L2_PIX_FMT_JPEG:
559
data->jdec = tinyjpeg_init();
561
return v4lconvert_oom_error(data);
563
tinyjpeg_set_flags(data->jdec, jpeg_flags);
564
if (tinyjpeg_parse_header(data->jdec, src, src_size)) {
565
V4LCONVERT_ERR("parsing JPEG header: %s",
566
tinyjpeg_get_errorstring(data->jdec));
570
tinyjpeg_get_size(data->jdec, &header_width, &header_height);
572
if (header_width != width || header_height != height) {
573
/* Check for (pixart) rotated JPEG */
574
if (header_width == height && header_height == width) {
575
if (!(data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) {
576
V4LCONVERT_ERR("JPEG needs 90° rotation, please report "
577
"this to <hdegoede@redhat.com>\n");
581
fmt->fmt.pix.width = header_width;
582
fmt->fmt.pix.height = header_height;
584
V4LCONVERT_ERR("unexpected width / height in JPEG header"
585
"expected: %ux%u, header: %ux%u\n", width, height,
586
header_width, header_height);
590
} else if ((data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) {
591
fprintf(stderr, "libv4lconvert: expected 90° rotated JPEG, but got "
592
"normal JPEG, please report this to <hdegoede@redhat.com>\n");
593
V4LCONVERT_ERR("expected 90° rotated JPEG, but got normal JPEG\n");
595
data->control_flags &= ~V4LCONTROL_ROTATED_90_JPEG;
599
components[0] = dest;
601
switch (dest_pix_fmt) {
602
case V4L2_PIX_FMT_RGB24:
603
tinyjpeg_set_components(data->jdec, components, 1);
604
result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_RGB24);
606
case V4L2_PIX_FMT_BGR24:
607
tinyjpeg_set_components(data->jdec, components, 1);
608
result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_BGR24);
610
case V4L2_PIX_FMT_YUV420:
611
components[1] = components[0] + width * height;
612
components[2] = components[1] + width * height / 4;
613
tinyjpeg_set_components(data->jdec, components, 3);
614
result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_YUV420P);
616
case V4L2_PIX_FMT_YVU420:
617
components[2] = components[0] + width * height;
618
components[1] = components[2] + width * height / 4;
619
tinyjpeg_set_components(data->jdec, components, 3);
620
result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_YUV420P);
625
/* Pixart webcam's seem to regulary generate corrupt frames, which
626
are best thrown away to avoid flashes in the video stream. Tell
627
the upper layer this is an intermediate fault and it should try
628
again with a new buffer by setting errno to EAGAIN */
629
if (src_pix_fmt == V4L2_PIX_FMT_PJPG ||
630
data->flags & V4LCONVERT_IS_SN9C20X) {
631
V4LCONVERT_ERR("decompressing JPEG: %s",
632
tinyjpeg_get_errorstring(data->jdec));
636
/* If the JPEG header checked out ok and we get an error during actual
637
decompression, log the error, but don't return an errorcode to the
638
application, so that the user gets what we managed to decompress */
639
fprintf(stderr, "libv4lconvert: Error decompressing JPEG: %s",
640
tinyjpeg_get_errorstring(data->jdec));
645
/* Custom cam specific YUV formats */
673
646
case V4L2_PIX_FMT_SPCA501:
674
v4lconvert_spca501_to_yuv420(src, d, width, height, yvu);
676
647
case V4L2_PIX_FMT_SPCA505:
677
v4lconvert_spca505_to_yuv420(src, d, width, height, yvu);
679
648
case V4L2_PIX_FMT_SPCA508:
680
v4lconvert_spca508_to_yuv420(src, d, width, height, yvu);
682
649
case V4L2_PIX_FMT_SN9C20X_I420:
683
v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu);
685
650
case V4L2_PIX_FMT_CPIA1:
686
if (v4lconvert_cpia1_to_yuv420(data, src, src_size, d,
687
width, height, yvu)) {
688
/* Corrupt frame, better get another one */
693
651
case V4L2_PIX_FMT_OV511:
694
if (v4lconvert_helper_decompress(data, LIBDIR "/" LIBSUBDIR "/ov511-decomp",
695
src, src_size, d, d_size, width, height, yvu)) {
696
/* Corrupt frame, better get another one */
701
case V4L2_PIX_FMT_OV518:
702
if (v4lconvert_helper_decompress(data, LIBDIR "/" LIBSUBDIR "/ov518-decomp",
703
src, src_size, d, d_size, width, height, yvu)) {
704
/* Corrupt frame, better get another one */
711
switch (dest_pix_fmt) {
712
case V4L2_PIX_FMT_RGB24:
713
v4lconvert_yuv420_to_rgb24(data->convert_pixfmt_buf, dest, width,
716
case V4L2_PIX_FMT_BGR24:
717
v4lconvert_yuv420_to_bgr24(data->convert_pixfmt_buf, dest, width,
724
/* Conexant cx2341x raw video macroblock format */
725
case V4L2_PIX_FMT_HM12:
726
switch (dest_pix_fmt) {
727
case V4L2_PIX_FMT_RGB24:
728
v4lconvert_hm12_to_rgb24(src, dest, width, height);
730
case V4L2_PIX_FMT_BGR24:
731
v4lconvert_hm12_to_bgr24(src, dest, width, height);
733
case V4L2_PIX_FMT_YUV420:
734
v4lconvert_hm12_to_yuv420(src, dest, width, height, 0);
736
case V4L2_PIX_FMT_YVU420:
737
v4lconvert_hm12_to_yuv420(src, dest, width, height, 1);
742
/* compressed bayer formats */
743
case V4L2_PIX_FMT_SPCA561:
744
case V4L2_PIX_FMT_SN9C10X:
745
case V4L2_PIX_FMT_PAC207:
746
case V4L2_PIX_FMT_MR97310A:
747
case V4L2_PIX_FMT_SN9C2028:
748
case V4L2_PIX_FMT_SQ905C:
749
case V4L2_PIX_FMT_STV0680: /* Not compressed but needs some shuffling */
751
unsigned char *tmpbuf;
752
struct v4l2_format tmpfmt = *fmt;
754
tmpbuf = v4lconvert_alloc_buffer(width * height,
755
&data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
757
return v4lconvert_oom_error(data);
759
switch (src_pix_fmt) {
652
case V4L2_PIX_FMT_OV518: {
657
if (dest_pix_fmt != V4L2_PIX_FMT_YUV420 &&
658
dest_pix_fmt != V4L2_PIX_FMT_YVU420) {
659
d = v4lconvert_alloc_buffer(width * height * 3 / 2,
660
&data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
662
return v4lconvert_oom_error(data);
663
d_size = width * height * 3 / 2;
669
if (dest_pix_fmt == V4L2_PIX_FMT_YVU420)
672
switch (src_pix_fmt) {
673
case V4L2_PIX_FMT_SPCA501:
674
v4lconvert_spca501_to_yuv420(src, d, width, height, yvu);
676
case V4L2_PIX_FMT_SPCA505:
677
v4lconvert_spca505_to_yuv420(src, d, width, height, yvu);
679
case V4L2_PIX_FMT_SPCA508:
680
v4lconvert_spca508_to_yuv420(src, d, width, height, yvu);
682
case V4L2_PIX_FMT_SN9C20X_I420:
683
v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu);
685
case V4L2_PIX_FMT_CPIA1:
686
if (v4lconvert_cpia1_to_yuv420(data, src, src_size, d,
687
width, height, yvu)) {
688
/* Corrupt frame, better get another one */
693
case V4L2_PIX_FMT_OV511:
694
if (v4lconvert_helper_decompress(data, LIBDIR "/" LIBSUBDIR "/ov511-decomp",
695
src, src_size, d, d_size, width, height, yvu)) {
696
/* Corrupt frame, better get another one */
701
case V4L2_PIX_FMT_OV518:
702
if (v4lconvert_helper_decompress(data, LIBDIR "/" LIBSUBDIR "/ov518-decomp",
703
src, src_size, d, d_size, width, height, yvu)) {
704
/* Corrupt frame, better get another one */
711
switch (dest_pix_fmt) {
712
case V4L2_PIX_FMT_RGB24:
713
v4lconvert_yuv420_to_rgb24(data->convert_pixfmt_buf, dest, width,
716
case V4L2_PIX_FMT_BGR24:
717
v4lconvert_yuv420_to_bgr24(data->convert_pixfmt_buf, dest, width,
724
/* Conexant cx2341x raw video macroblock format */
725
case V4L2_PIX_FMT_HM12:
726
switch (dest_pix_fmt) {
727
case V4L2_PIX_FMT_RGB24:
728
v4lconvert_hm12_to_rgb24(src, dest, width, height);
730
case V4L2_PIX_FMT_BGR24:
731
v4lconvert_hm12_to_bgr24(src, dest, width, height);
733
case V4L2_PIX_FMT_YUV420:
734
v4lconvert_hm12_to_yuv420(src, dest, width, height, 0);
736
case V4L2_PIX_FMT_YVU420:
737
v4lconvert_hm12_to_yuv420(src, dest, width, height, 1);
742
/* compressed bayer formats */
760
743
case V4L2_PIX_FMT_SPCA561:
761
v4lconvert_decode_spca561(src, tmpbuf, width, height);
762
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGBRG8;
764
744
case V4L2_PIX_FMT_SN9C10X:
765
v4lconvert_decode_sn9c10x(src, tmpbuf, width, height);
766
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
768
745
case V4L2_PIX_FMT_PAC207:
769
if (v4lconvert_decode_pac207(data, src, src_size, tmpbuf,
771
/* Corrupt frame, better get another one */
775
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
777
746
case V4L2_PIX_FMT_MR97310A:
778
if (v4lconvert_decode_mr97310a(data, src, src_size, tmpbuf,
780
/* Corrupt frame, better get another one */
784
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
786
747
case V4L2_PIX_FMT_SN9C2028:
787
v4lconvert_decode_sn9c2028(src, tmpbuf, width, height);
788
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
790
748
case V4L2_PIX_FMT_SQ905C:
791
v4lconvert_decode_sq905c(src, tmpbuf, width, height);
792
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
794
case V4L2_PIX_FMT_STV0680:
795
v4lconvert_decode_stv0680(src, tmpbuf, width, height);
796
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
799
/* Do processing on the tmp buffer, because doing it on bayer data is
800
cheaper, and bayer == rgb and our dest_fmt may be yuv */
801
tmpfmt.fmt.pix.bytesperline = width;
802
tmpfmt.fmt.pix.sizeimage = width * height;
803
v4lprocessing_processing(data->processing, tmpbuf, &tmpfmt);
804
/* Deliberate fall through to raw bayer fmt code! */
805
src_pix_fmt = tmpfmt.fmt.pix.pixelformat;
809
/* Raw bayer formats */
810
case V4L2_PIX_FMT_SBGGR8:
811
case V4L2_PIX_FMT_SGBRG8:
812
case V4L2_PIX_FMT_SGRBG8:
813
case V4L2_PIX_FMT_SRGGB8:
814
switch (dest_pix_fmt) {
815
case V4L2_PIX_FMT_RGB24:
816
v4lconvert_bayer_to_rgb24(src, dest, width, height, src_pix_fmt);
818
case V4L2_PIX_FMT_BGR24:
819
v4lconvert_bayer_to_bgr24(src, dest, width, height, src_pix_fmt);
821
case V4L2_PIX_FMT_YUV420:
822
v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 0);
824
case V4L2_PIX_FMT_YVU420:
825
v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 1);
830
case V4L2_PIX_FMT_RGB565:
831
switch (dest_pix_fmt) {
832
case V4L2_PIX_FMT_RGB24:
833
v4lconvert_rgb565_to_rgb24(src, dest, width, height);
835
case V4L2_PIX_FMT_BGR24:
836
v4lconvert_rgb565_to_bgr24(src, dest, width, height);
838
case V4L2_PIX_FMT_YUV420:
839
v4lconvert_rgb565_to_yuv420(src, dest, fmt, 0);
841
case V4L2_PIX_FMT_YVU420:
842
v4lconvert_rgb565_to_yuv420(src, dest, fmt, 1);
847
case V4L2_PIX_FMT_RGB24:
848
switch (dest_pix_fmt) {
849
case V4L2_PIX_FMT_BGR24:
850
v4lconvert_swap_rgb(src, dest, width, height);
852
case V4L2_PIX_FMT_YUV420:
853
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 0);
855
case V4L2_PIX_FMT_YVU420:
856
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 1);
861
case V4L2_PIX_FMT_BGR24:
862
switch (dest_pix_fmt) {
863
case V4L2_PIX_FMT_RGB24:
864
v4lconvert_swap_rgb(src, dest, width, height);
866
case V4L2_PIX_FMT_YUV420:
867
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 0);
869
case V4L2_PIX_FMT_YVU420:
870
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 1);
875
case V4L2_PIX_FMT_YUV420:
876
switch (dest_pix_fmt) {
877
case V4L2_PIX_FMT_RGB24:
878
v4lconvert_yuv420_to_rgb24(src, dest, width,
881
case V4L2_PIX_FMT_BGR24:
882
v4lconvert_yuv420_to_bgr24(src, dest, width,
885
case V4L2_PIX_FMT_YVU420:
886
v4lconvert_swap_uv(src, dest, fmt);
891
case V4L2_PIX_FMT_YVU420:
892
switch (dest_pix_fmt) {
893
case V4L2_PIX_FMT_RGB24:
894
v4lconvert_yuv420_to_rgb24(src, dest, width,
897
case V4L2_PIX_FMT_BGR24:
898
v4lconvert_yuv420_to_bgr24(src, dest, width,
901
case V4L2_PIX_FMT_YUV420:
902
v4lconvert_swap_uv(src, dest, fmt);
907
case V4L2_PIX_FMT_YUYV:
908
switch (dest_pix_fmt) {
909
case V4L2_PIX_FMT_RGB24:
910
v4lconvert_yuyv_to_rgb24(src, dest, width, height);
912
case V4L2_PIX_FMT_BGR24:
913
v4lconvert_yuyv_to_bgr24(src, dest, width, height);
915
case V4L2_PIX_FMT_YUV420:
916
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 0);
918
case V4L2_PIX_FMT_YVU420:
919
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 1);
924
case V4L2_PIX_FMT_YVYU:
925
switch (dest_pix_fmt) {
926
case V4L2_PIX_FMT_RGB24:
927
v4lconvert_yvyu_to_rgb24(src, dest, width, height);
929
case V4L2_PIX_FMT_BGR24:
930
v4lconvert_yvyu_to_bgr24(src, dest, width, height);
932
case V4L2_PIX_FMT_YUV420:
933
/* Note we use yuyv_to_yuv420 not v4lconvert_yvyu_to_yuv420,
934
with the last argument reversed to make it have as we want */
935
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 1);
937
case V4L2_PIX_FMT_YVU420:
938
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 0);
943
case V4L2_PIX_FMT_UYVY:
944
switch (dest_pix_fmt) {
945
case V4L2_PIX_FMT_RGB24:
946
v4lconvert_uyvy_to_rgb24(src, dest, width, height);
948
case V4L2_PIX_FMT_BGR24:
949
v4lconvert_uyvy_to_bgr24(src, dest, width, height);
951
case V4L2_PIX_FMT_YUV420:
952
v4lconvert_uyvy_to_yuv420(src, dest, width, height, 0);
954
case V4L2_PIX_FMT_YVU420:
955
v4lconvert_uyvy_to_yuv420(src, dest, width, height, 1);
961
V4LCONVERT_ERR("Unknown src format in conversion\n");
966
fmt->fmt.pix.pixelformat = dest_pix_fmt;
967
v4lconvert_fixup_fmt(fmt);
749
case V4L2_PIX_FMT_STV0680: { /* Not compressed but needs some shuffling */
750
unsigned char *tmpbuf;
751
struct v4l2_format tmpfmt = *fmt;
753
tmpbuf = v4lconvert_alloc_buffer(width * height,
754
&data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
756
return v4lconvert_oom_error(data);
758
switch (src_pix_fmt) {
759
case V4L2_PIX_FMT_SPCA561:
760
v4lconvert_decode_spca561(src, tmpbuf, width, height);
761
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGBRG8;
763
case V4L2_PIX_FMT_SN9C10X:
764
v4lconvert_decode_sn9c10x(src, tmpbuf, width, height);
765
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
767
case V4L2_PIX_FMT_PAC207:
768
if (v4lconvert_decode_pac207(data, src, src_size, tmpbuf,
770
/* Corrupt frame, better get another one */
774
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
776
case V4L2_PIX_FMT_MR97310A:
777
if (v4lconvert_decode_mr97310a(data, src, src_size, tmpbuf,
779
/* Corrupt frame, better get another one */
783
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
785
case V4L2_PIX_FMT_SN9C2028:
786
v4lconvert_decode_sn9c2028(src, tmpbuf, width, height);
787
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
789
case V4L2_PIX_FMT_SQ905C:
790
v4lconvert_decode_sq905c(src, tmpbuf, width, height);
791
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
793
case V4L2_PIX_FMT_STV0680:
794
v4lconvert_decode_stv0680(src, tmpbuf, width, height);
795
tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
798
/* Do processing on the tmp buffer, because doing it on bayer data is
799
cheaper, and bayer == rgb and our dest_fmt may be yuv */
800
tmpfmt.fmt.pix.bytesperline = width;
801
tmpfmt.fmt.pix.sizeimage = width * height;
802
v4lprocessing_processing(data->processing, tmpbuf, &tmpfmt);
803
/* Deliberate fall through to raw bayer fmt code! */
804
src_pix_fmt = tmpfmt.fmt.pix.pixelformat;
809
/* Raw bayer formats */
810
case V4L2_PIX_FMT_SBGGR8:
811
case V4L2_PIX_FMT_SGBRG8:
812
case V4L2_PIX_FMT_SGRBG8:
813
case V4L2_PIX_FMT_SRGGB8:
814
switch (dest_pix_fmt) {
815
case V4L2_PIX_FMT_RGB24:
816
v4lconvert_bayer_to_rgb24(src, dest, width, height, src_pix_fmt);
818
case V4L2_PIX_FMT_BGR24:
819
v4lconvert_bayer_to_bgr24(src, dest, width, height, src_pix_fmt);
821
case V4L2_PIX_FMT_YUV420:
822
v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 0);
824
case V4L2_PIX_FMT_YVU420:
825
v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 1);
830
case V4L2_PIX_FMT_RGB565:
831
switch (dest_pix_fmt) {
832
case V4L2_PIX_FMT_RGB24:
833
v4lconvert_rgb565_to_rgb24(src, dest, width, height);
835
case V4L2_PIX_FMT_BGR24:
836
v4lconvert_rgb565_to_bgr24(src, dest, width, height);
838
case V4L2_PIX_FMT_YUV420:
839
v4lconvert_rgb565_to_yuv420(src, dest, fmt, 0);
841
case V4L2_PIX_FMT_YVU420:
842
v4lconvert_rgb565_to_yuv420(src, dest, fmt, 1);
847
case V4L2_PIX_FMT_RGB24:
848
switch (dest_pix_fmt) {
849
case V4L2_PIX_FMT_BGR24:
850
v4lconvert_swap_rgb(src, dest, width, height);
852
case V4L2_PIX_FMT_YUV420:
853
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 0);
855
case V4L2_PIX_FMT_YVU420:
856
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 1);
861
case V4L2_PIX_FMT_BGR24:
862
switch (dest_pix_fmt) {
863
case V4L2_PIX_FMT_RGB24:
864
v4lconvert_swap_rgb(src, dest, width, height);
866
case V4L2_PIX_FMT_YUV420:
867
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 0);
869
case V4L2_PIX_FMT_YVU420:
870
v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 1);
875
case V4L2_PIX_FMT_YUV420:
876
switch (dest_pix_fmt) {
877
case V4L2_PIX_FMT_RGB24:
878
v4lconvert_yuv420_to_rgb24(src, dest, width,
881
case V4L2_PIX_FMT_BGR24:
882
v4lconvert_yuv420_to_bgr24(src, dest, width,
885
case V4L2_PIX_FMT_YVU420:
886
v4lconvert_swap_uv(src, dest, fmt);
891
case V4L2_PIX_FMT_YVU420:
892
switch (dest_pix_fmt) {
893
case V4L2_PIX_FMT_RGB24:
894
v4lconvert_yuv420_to_rgb24(src, dest, width,
897
case V4L2_PIX_FMT_BGR24:
898
v4lconvert_yuv420_to_bgr24(src, dest, width,
901
case V4L2_PIX_FMT_YUV420:
902
v4lconvert_swap_uv(src, dest, fmt);
907
case V4L2_PIX_FMT_YUYV:
908
switch (dest_pix_fmt) {
909
case V4L2_PIX_FMT_RGB24:
910
v4lconvert_yuyv_to_rgb24(src, dest, width, height);
912
case V4L2_PIX_FMT_BGR24:
913
v4lconvert_yuyv_to_bgr24(src, dest, width, height);
915
case V4L2_PIX_FMT_YUV420:
916
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 0);
918
case V4L2_PIX_FMT_YVU420:
919
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 1);
924
case V4L2_PIX_FMT_YVYU:
925
switch (dest_pix_fmt) {
926
case V4L2_PIX_FMT_RGB24:
927
v4lconvert_yvyu_to_rgb24(src, dest, width, height);
929
case V4L2_PIX_FMT_BGR24:
930
v4lconvert_yvyu_to_bgr24(src, dest, width, height);
932
case V4L2_PIX_FMT_YUV420:
933
/* Note we use yuyv_to_yuv420 not v4lconvert_yvyu_to_yuv420,
934
with the last argument reversed to make it have as we want */
935
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 1);
937
case V4L2_PIX_FMT_YVU420:
938
v4lconvert_yuyv_to_yuv420(src, dest, width, height, 0);
943
case V4L2_PIX_FMT_UYVY:
944
switch (dest_pix_fmt) {
945
case V4L2_PIX_FMT_RGB24:
946
v4lconvert_uyvy_to_rgb24(src, dest, width, height);
948
case V4L2_PIX_FMT_BGR24:
949
v4lconvert_uyvy_to_bgr24(src, dest, width, height);
951
case V4L2_PIX_FMT_YUV420:
952
v4lconvert_uyvy_to_yuv420(src, dest, width, height, 0);
954
case V4L2_PIX_FMT_YVU420:
955
v4lconvert_uyvy_to_yuv420(src, dest, width, height, 1);
961
V4LCONVERT_ERR("Unknown src format in conversion\n");
966
fmt->fmt.pix.pixelformat = dest_pix_fmt;
967
v4lconvert_fixup_fmt(fmt);
972
972
int v4lconvert_convert(struct v4lconvert_data *data,
973
const struct v4l2_format *src_fmt, /* in */
974
const struct v4l2_format *dest_fmt, /* in */
975
unsigned char *src, int src_size, unsigned char *dest, int dest_size)
973
const struct v4l2_format *src_fmt, /* in */
974
const struct v4l2_format *dest_fmt, /* in */
975
unsigned char *src, int src_size, unsigned char *dest, int dest_size)
977
int res, dest_needed, temp_needed, processing, convert = 0;
978
int rotate90, vflip, hflip, crop;
979
unsigned char *convert1_dest = dest;
980
int convert1_dest_size = dest_size;
981
unsigned char *convert2_src = src, *convert2_dest = dest;
982
int convert2_dest_size = dest_size;
983
unsigned char *rotate90_src = src, *rotate90_dest = dest;
984
unsigned char *flip_src = src, *flip_dest = dest;
985
unsigned char *crop_src = src;
986
struct v4l2_format my_src_fmt = *src_fmt;
987
struct v4l2_format my_dest_fmt = *dest_fmt;
989
processing = v4lprocessing_pre_processing(data->processing);
990
rotate90 = data->control_flags & V4LCONTROL_ROTATED_90_JPEG;
991
hflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_HFLIP);
992
vflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_VFLIP);
993
crop = my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width ||
994
my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height;
996
if (/* If no conversion/processing is needed */
997
(src_fmt->fmt.pix.pixelformat == dest_fmt->fmt.pix.pixelformat &&
998
!processing && !rotate90 && !hflip && !vflip && !crop) ||
999
/* or if we should do processing/rotating/flipping but the app tries to
1000
use the native cam format, we just return an unprocessed frame copy */
1001
!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) {
1002
int to_copy = MIN(dest_size, src_size);
1003
memcpy(dest, src, to_copy);
1007
/* When field is V4L2_FIELD_ALTERNATE, each buffer only contains half the
1009
if (my_src_fmt.fmt.pix.field == V4L2_FIELD_ALTERNATE) {
1010
my_src_fmt.fmt.pix.height /= 2;
1011
my_dest_fmt.fmt.pix.height /= 2;
1014
/* sanity check, is the dest buffer large enough? */
1015
switch (my_dest_fmt.fmt.pix.pixelformat) {
1016
case V4L2_PIX_FMT_RGB24:
1017
case V4L2_PIX_FMT_BGR24:
1018
dest_needed = my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3;
1019
temp_needed = my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
1021
case V4L2_PIX_FMT_YUV420:
1022
case V4L2_PIX_FMT_YVU420:
1024
my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3 / 2;
1026
my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3 / 2;
1029
V4LCONVERT_ERR("Unknown dest format in conversion\n");
1034
if (dest_size < dest_needed) {
1035
V4LCONVERT_ERR("destination buffer too small (%d < %d)\n",
1036
dest_size, dest_needed);
1042
/* Sometimes we need foo -> rgb -> bar as video processing (whitebalance,
1043
etc.) can only be done on rgb data */
1044
if (processing && v4lconvert_processing_needs_double_conversion(
1045
my_src_fmt.fmt.pix.pixelformat,
1046
my_dest_fmt.fmt.pix.pixelformat))
1048
else if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat)
1051
/* convert_pixfmt (only if convert == 2) -> processing -> convert_pixfmt ->
1052
rotate -> flip -> crop, all steps are optional */
1054
convert1_dest = v4lconvert_alloc_buffer(
1055
my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3,
1056
&data->convert1_buf, &data->convert1_buf_size);
1058
return v4lconvert_oom_error(data);
1060
convert1_dest_size =
1061
my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
1062
convert2_src = convert1_dest;
1065
if (convert && (rotate90 || hflip || vflip || crop)) {
1066
convert2_dest = v4lconvert_alloc_buffer(temp_needed,
1067
&data->convert2_buf, &data->convert2_buf_size);
1069
return v4lconvert_oom_error(data);
1071
convert2_dest_size = temp_needed;
1072
rotate90_src = flip_src = crop_src = convert2_dest;
1075
if (rotate90 && (hflip || vflip || crop)) {
1076
rotate90_dest = v4lconvert_alloc_buffer(temp_needed,
1077
&data->rotate90_buf, &data->rotate90_buf_size);
1079
return v4lconvert_oom_error(data);
1081
flip_src = crop_src = rotate90_dest;
1084
if ((vflip || hflip) && crop) {
1085
flip_dest = v4lconvert_alloc_buffer(temp_needed, &data->flip_buf,
1086
&data->flip_buf_size);
1088
return v4lconvert_oom_error(data);
1090
crop_src = flip_dest;
1093
/* Done setting sources / dest and allocating intermediate buffers,
1094
real conversion / processing / ... starts here. */
1096
res = v4lconvert_convert_pixfmt(data, src, src_size,
1097
convert1_dest, convert1_dest_size,
1099
V4L2_PIX_FMT_RGB24);
1103
src_size = my_src_fmt.fmt.pix.sizeimage;
1107
v4lprocessing_processing(data->processing, convert2_src, &my_src_fmt);
1110
res = v4lconvert_convert_pixfmt(data, convert2_src, src_size,
1111
convert2_dest, convert2_dest_size,
1113
my_dest_fmt.fmt.pix.pixelformat);
1117
src_size = my_src_fmt.fmt.pix.sizeimage;
1119
/* We call processing here again in case the source format was not
1120
rgb, but the dest is. v4lprocessing checks it self it only actually
1121
does the processing once per frame. */
1123
v4lprocessing_processing(data->processing, convert2_dest, &my_src_fmt);
1127
v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt);
1130
v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, hflip, vflip);
1133
v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt);
977
int res, dest_needed, temp_needed, processing, convert = 0;
978
int rotate90, vflip, hflip, crop;
979
unsigned char *convert1_dest = dest;
980
int convert1_dest_size = dest_size;
981
unsigned char *convert2_src = src, *convert2_dest = dest;
982
int convert2_dest_size = dest_size;
983
unsigned char *rotate90_src = src, *rotate90_dest = dest;
984
unsigned char *flip_src = src, *flip_dest = dest;
985
unsigned char *crop_src = src;
986
struct v4l2_format my_src_fmt = *src_fmt;
987
struct v4l2_format my_dest_fmt = *dest_fmt;
989
processing = v4lprocessing_pre_processing(data->processing);
990
rotate90 = data->control_flags & V4LCONTROL_ROTATED_90_JPEG;
991
hflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_HFLIP);
992
vflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_VFLIP);
993
crop = my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width ||
994
my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height;
996
if (/* If no conversion/processing is needed */
997
(src_fmt->fmt.pix.pixelformat == dest_fmt->fmt.pix.pixelformat &&
998
!processing && !rotate90 && !hflip && !vflip && !crop) ||
999
/* or if we should do processing/rotating/flipping but the app tries to
1000
use the native cam format, we just return an unprocessed frame copy */
1001
!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) {
1002
int to_copy = MIN(dest_size, src_size);
1003
memcpy(dest, src, to_copy);
1007
/* When field is V4L2_FIELD_ALTERNATE, each buffer only contains half the
1009
if (my_src_fmt.fmt.pix.field == V4L2_FIELD_ALTERNATE) {
1010
my_src_fmt.fmt.pix.height /= 2;
1011
my_dest_fmt.fmt.pix.height /= 2;
1014
/* sanity check, is the dest buffer large enough? */
1015
switch (my_dest_fmt.fmt.pix.pixelformat) {
1016
case V4L2_PIX_FMT_RGB24:
1017
case V4L2_PIX_FMT_BGR24:
1018
dest_needed = my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3;
1019
temp_needed = my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
1021
case V4L2_PIX_FMT_YUV420:
1022
case V4L2_PIX_FMT_YVU420:
1024
my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3 / 2;
1026
my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3 / 2;
1029
V4LCONVERT_ERR("Unknown dest format in conversion\n");
1034
if (dest_size < dest_needed) {
1035
V4LCONVERT_ERR("destination buffer too small (%d < %d)\n",
1036
dest_size, dest_needed);
1042
/* Sometimes we need foo -> rgb -> bar as video processing (whitebalance,
1043
etc.) can only be done on rgb data */
1044
if (processing && v4lconvert_processing_needs_double_conversion(
1045
my_src_fmt.fmt.pix.pixelformat,
1046
my_dest_fmt.fmt.pix.pixelformat))
1048
else if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat)
1051
/* convert_pixfmt (only if convert == 2) -> processing -> convert_pixfmt ->
1052
rotate -> flip -> crop, all steps are optional */
1054
convert1_dest = v4lconvert_alloc_buffer(
1055
my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3,
1056
&data->convert1_buf, &data->convert1_buf_size);
1058
return v4lconvert_oom_error(data);
1060
convert1_dest_size =
1061
my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
1062
convert2_src = convert1_dest;
1065
if (convert && (rotate90 || hflip || vflip || crop)) {
1066
convert2_dest = v4lconvert_alloc_buffer(temp_needed,
1067
&data->convert2_buf, &data->convert2_buf_size);
1069
return v4lconvert_oom_error(data);
1071
convert2_dest_size = temp_needed;
1072
rotate90_src = flip_src = crop_src = convert2_dest;
1075
if (rotate90 && (hflip || vflip || crop)) {
1076
rotate90_dest = v4lconvert_alloc_buffer(temp_needed,
1077
&data->rotate90_buf, &data->rotate90_buf_size);
1079
return v4lconvert_oom_error(data);
1081
flip_src = crop_src = rotate90_dest;
1084
if ((vflip || hflip) && crop) {
1085
flip_dest = v4lconvert_alloc_buffer(temp_needed, &data->flip_buf,
1086
&data->flip_buf_size);
1088
return v4lconvert_oom_error(data);
1090
crop_src = flip_dest;
1093
/* Done setting sources / dest and allocating intermediate buffers,
1094
real conversion / processing / ... starts here. */
1096
res = v4lconvert_convert_pixfmt(data, src, src_size,
1097
convert1_dest, convert1_dest_size,
1099
V4L2_PIX_FMT_RGB24);
1103
src_size = my_src_fmt.fmt.pix.sizeimage;
1107
v4lprocessing_processing(data->processing, convert2_src, &my_src_fmt);
1110
res = v4lconvert_convert_pixfmt(data, convert2_src, src_size,
1111
convert2_dest, convert2_dest_size,
1113
my_dest_fmt.fmt.pix.pixelformat);
1117
src_size = my_src_fmt.fmt.pix.sizeimage;
1119
/* We call processing here again in case the source format was not
1120
rgb, but the dest is. v4lprocessing checks it self it only actually
1121
does the processing once per frame. */
1123
v4lprocessing_processing(data->processing, convert2_dest, &my_src_fmt);
1127
v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt);
1130
v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, hflip, vflip);
1133
v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt);
1138
1138
const char *v4lconvert_get_error_message(struct v4lconvert_data *data)
1140
return data->error_msg;
1140
return data->error_msg;
1143
1143
static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
1144
unsigned int pixelformat, int index)
1144
unsigned int pixelformat, int index)
1147
struct v4l2_frmsizeenum frmsize = { .pixel_format = pixelformat };
1149
for (i = 0; ; i++) {
1151
if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize))
1154
/* We got a framesize, check we don't have the same one already */
1156
for (j = 0; j < data->no_framesizes; j++) {
1157
if (frmsize.type != data->framesizes[j].type)
1160
switch(frmsize.type) {
1161
case V4L2_FRMSIZE_TYPE_DISCRETE:
1162
if(!memcmp(&frmsize.discrete, &data->framesizes[j].discrete,
1163
sizeof(frmsize.discrete)))
1166
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1167
case V4L2_FRMSIZE_TYPE_STEPWISE:
1168
if(!memcmp(&frmsize.stepwise, &data->framesizes[j].stepwise,
1169
sizeof(frmsize.stepwise)))
1176
/* Add this framesize if it is not already in our list */
1178
if (data->no_framesizes == V4LCONVERT_MAX_FRAMESIZES) {
1180
"libv4lconvert: warning more framesizes then I can handle!\n");
1183
data->framesizes[data->no_framesizes].type = frmsize.type;
1184
/* We use the pixel_format member to store a bitmask of all
1185
supported src_formats which can do this size */
1186
data->framesizes[data->no_framesizes].pixel_format = 1 << index;
1187
switch(frmsize.type) {
1188
case V4L2_FRMSIZE_TYPE_DISCRETE:
1189
data->framesizes[data->no_framesizes].discrete = frmsize.discrete;
1191
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1192
case V4L2_FRMSIZE_TYPE_STEPWISE:
1193
data->framesizes[data->no_framesizes].stepwise = frmsize.stepwise;
1196
data->no_framesizes++;
1199
data->framesizes[j].pixel_format |= 1 << index;
1147
struct v4l2_frmsizeenum frmsize = { .pixel_format = pixelformat };
1149
for (i = 0; ; i++) {
1151
if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize))
1154
/* We got a framesize, check we don't have the same one already */
1156
for (j = 0; j < data->no_framesizes; j++) {
1157
if (frmsize.type != data->framesizes[j].type)
1160
switch (frmsize.type) {
1161
case V4L2_FRMSIZE_TYPE_DISCRETE:
1162
if (!memcmp(&frmsize.discrete, &data->framesizes[j].discrete,
1163
sizeof(frmsize.discrete)))
1166
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1167
case V4L2_FRMSIZE_TYPE_STEPWISE:
1168
if (!memcmp(&frmsize.stepwise, &data->framesizes[j].stepwise,
1169
sizeof(frmsize.stepwise)))
1176
/* Add this framesize if it is not already in our list */
1178
if (data->no_framesizes == V4LCONVERT_MAX_FRAMESIZES) {
1179
fprintf(stderr, "libv4lconvert: warning more framesizes then I can handle!\n");
1182
data->framesizes[data->no_framesizes].type = frmsize.type;
1183
/* We use the pixel_format member to store a bitmask of all
1184
supported src_formats which can do this size */
1185
data->framesizes[data->no_framesizes].pixel_format = 1 << index;
1187
switch (frmsize.type) {
1188
case V4L2_FRMSIZE_TYPE_DISCRETE:
1189
data->framesizes[data->no_framesizes].discrete = frmsize.discrete;
1191
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1192
case V4L2_FRMSIZE_TYPE_STEPWISE:
1193
data->framesizes[data->no_framesizes].stepwise = frmsize.stepwise;
1196
data->no_framesizes++;
1198
data->framesizes[j].pixel_format |= 1 << index;
1203
1203
int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
1204
struct v4l2_frmsizeenum *frmsize)
1204
struct v4l2_frmsizeenum *frmsize)
1206
if (!v4lconvert_supported_dst_format(frmsize->pixel_format)) {
1207
if (v4lconvert_supported_dst_fmt_only(data)) {
1211
return SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize);
1214
if (frmsize->index >= data->no_framesizes) {
1219
frmsize->type = data->framesizes[frmsize->index].type;
1220
switch(frmsize->type) {
1221
case V4L2_FRMSIZE_TYPE_DISCRETE:
1222
frmsize->discrete = data->framesizes[frmsize->index].discrete;
1223
/* Apply the same rounding algorithm as v4lconvert_try_format */
1224
frmsize->discrete.width &= ~7;
1225
frmsize->discrete.height &= ~1;
1227
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1228
case V4L2_FRMSIZE_TYPE_STEPWISE:
1229
frmsize->stepwise = data->framesizes[frmsize->index].stepwise;
1206
if (!v4lconvert_supported_dst_format(frmsize->pixel_format)) {
1207
if (v4lconvert_supported_dst_fmt_only(data)) {
1211
return SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize);
1214
if (frmsize->index >= data->no_framesizes) {
1219
frmsize->type = data->framesizes[frmsize->index].type;
1220
switch (frmsize->type) {
1221
case V4L2_FRMSIZE_TYPE_DISCRETE:
1222
frmsize->discrete = data->framesizes[frmsize->index].discrete;
1223
/* Apply the same rounding algorithm as v4lconvert_try_format */
1224
frmsize->discrete.width &= ~7;
1225
frmsize->discrete.height &= ~1;
1227
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1228
case V4L2_FRMSIZE_TYPE_STEPWISE:
1229
frmsize->stepwise = data->framesizes[frmsize->index].stepwise;
1236
1236
int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
1237
struct v4l2_frmivalenum *frmival)
1240
struct v4l2_format src_fmt, dest_fmt;
1242
if (!v4lconvert_supported_dst_format(frmival->pixel_format)) {
1243
if (v4lconvert_supported_dst_fmt_only(data)) {
1247
res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
1249
V4LCONVERT_ERR("%s\n", strerror(errno));
1253
/* Check which format we will be using to convert to frmival->pixel_format */
1254
memset(&dest_fmt, 0, sizeof(dest_fmt));
1255
dest_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1256
dest_fmt.fmt.pix.pixelformat = frmival->pixel_format;
1257
dest_fmt.fmt.pix.width = frmival->width;
1258
dest_fmt.fmt.pix.height = frmival->height;
1259
if ((res = v4lconvert_try_format(data, &dest_fmt, &src_fmt))) {
1261
V4LCONVERT_ERR("trying format: %s\n", strerror(errno));
1265
/* Check the requested format is supported exactly as requested */
1266
if (dest_fmt.fmt.pix.pixelformat != frmival->pixel_format ||
1267
dest_fmt.fmt.pix.width != frmival->width ||
1268
dest_fmt.fmt.pix.height != frmival->height) {
1269
int frmival_pixformat = frmival->pixel_format;
1270
int dest_pixformat = dest_fmt.fmt.pix.pixelformat;
1271
V4LCONVERT_ERR("Could not find matching framesize for: %c%c%c%c %dx%d "
1272
"closest match: %c%c%c%c %dx%d\n",
1273
frmival_pixformat & 0xff,
1274
(frmival_pixformat >> 8) & 0xff,
1275
(frmival_pixformat >> 16) & 0xff,
1276
frmival_pixformat >> 24,
1277
frmival->width, frmival->height,
1278
dest_pixformat & 0xff,
1279
(dest_pixformat >> 8) & 0xff,
1280
(dest_pixformat >> 16) & 0xff,
1281
dest_pixformat >> 24,
1282
dest_fmt.fmt.pix.width , dest_fmt.fmt.pix.height);
1287
/* Enumerate the frameintervals of the source format we will be using */
1288
frmival->pixel_format = src_fmt.fmt.pix.pixelformat;
1289
frmival->width = src_fmt.fmt.pix.width;
1290
frmival->height = src_fmt.fmt.pix.height;
1291
res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
1293
int dest_pixfmt = dest_fmt.fmt.pix.pixelformat;
1294
int src_pixfmt = src_fmt.fmt.pix.pixelformat;
1295
V4LCONVERT_ERR("Could not enum frameival index: %d for: %c%c%c%c %dx%d "
1296
"using src: %c%c%c%c %dx%d, error: %s\n",
1299
(dest_pixfmt >> 8) & 0xff,
1300
(dest_pixfmt >> 16) & 0xff,
1302
dest_fmt.fmt.pix.width , dest_fmt.fmt.pix.height,
1304
(src_pixfmt >> 8) & 0xff,
1305
(src_pixfmt >> 16) & 0xff,
1307
src_fmt.fmt.pix.width, src_fmt.fmt.pix.height, strerror(errno));
1310
/* Restore the requested format in the frmival struct */
1311
frmival->pixel_format = dest_fmt.fmt.pix.pixelformat;
1312
frmival->width = dest_fmt.fmt.pix.width;
1313
frmival->height = dest_fmt.fmt.pix.height;
1318
int v4lconvert_vidioc_queryctrl(struct v4lconvert_data *data, void *arg) {
1319
return v4lcontrol_vidioc_queryctrl(data->control, arg);
1322
int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data, void *arg) {
1323
return v4lcontrol_vidioc_g_ctrl(data->control, arg);
1326
int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data, void *arg){
1327
return v4lcontrol_vidioc_s_ctrl(data->control, arg);
1237
struct v4l2_frmivalenum *frmival)
1240
struct v4l2_format src_fmt, dest_fmt;
1242
if (!v4lconvert_supported_dst_format(frmival->pixel_format)) {
1243
if (v4lconvert_supported_dst_fmt_only(data)) {
1247
res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
1249
V4LCONVERT_ERR("%s\n", strerror(errno));
1253
/* Check which format we will be using to convert to frmival->pixel_format */
1254
memset(&dest_fmt, 0, sizeof(dest_fmt));
1255
dest_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1256
dest_fmt.fmt.pix.pixelformat = frmival->pixel_format;
1257
dest_fmt.fmt.pix.width = frmival->width;
1258
dest_fmt.fmt.pix.height = frmival->height;
1259
res = v4lconvert_try_format(data, &dest_fmt, &src_fmt);
1261
V4LCONVERT_ERR("trying format: %s\n", strerror(errno));
1265
/* Check the requested format is supported exactly as requested */
1266
if (dest_fmt.fmt.pix.pixelformat != frmival->pixel_format ||
1267
dest_fmt.fmt.pix.width != frmival->width ||
1268
dest_fmt.fmt.pix.height != frmival->height) {
1269
int frmival_pixformat = frmival->pixel_format;
1270
int dest_pixformat = dest_fmt.fmt.pix.pixelformat;
1272
V4LCONVERT_ERR("Could not find matching framesize for: %c%c%c%c %dx%d "
1273
"closest match: %c%c%c%c %dx%d\n",
1274
frmival_pixformat & 0xff,
1275
(frmival_pixformat >> 8) & 0xff,
1276
(frmival_pixformat >> 16) & 0xff,
1277
frmival_pixformat >> 24,
1278
frmival->width, frmival->height,
1279
dest_pixformat & 0xff,
1280
(dest_pixformat >> 8) & 0xff,
1281
(dest_pixformat >> 16) & 0xff,
1282
dest_pixformat >> 24,
1283
dest_fmt.fmt.pix.width , dest_fmt.fmt.pix.height);
1288
/* Enumerate the frameintervals of the source format we will be using */
1289
frmival->pixel_format = src_fmt.fmt.pix.pixelformat;
1290
frmival->width = src_fmt.fmt.pix.width;
1291
frmival->height = src_fmt.fmt.pix.height;
1292
res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
1294
int dest_pixfmt = dest_fmt.fmt.pix.pixelformat;
1295
int src_pixfmt = src_fmt.fmt.pix.pixelformat;
1297
V4LCONVERT_ERR("Could not enum frameival index: %d for: %c%c%c%c %dx%d "
1298
"using src: %c%c%c%c %dx%d, error: %s\n",
1301
(dest_pixfmt >> 8) & 0xff,
1302
(dest_pixfmt >> 16) & 0xff,
1304
dest_fmt.fmt.pix.width , dest_fmt.fmt.pix.height,
1306
(src_pixfmt >> 8) & 0xff,
1307
(src_pixfmt >> 16) & 0xff,
1309
src_fmt.fmt.pix.width, src_fmt.fmt.pix.height, strerror(errno));
1312
/* Restore the requested format in the frmival struct */
1313
frmival->pixel_format = dest_fmt.fmt.pix.pixelformat;
1314
frmival->width = dest_fmt.fmt.pix.width;
1315
frmival->height = dest_fmt.fmt.pix.height;
1320
int v4lconvert_vidioc_queryctrl(struct v4lconvert_data *data, void *arg)
1322
return v4lcontrol_vidioc_queryctrl(data->control, arg);
1325
int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data, void *arg)
1327
return v4lcontrol_vidioc_g_ctrl(data->control, arg);
1330
int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data, void *arg)
1332
return v4lcontrol_vidioc_s_ctrl(data->control, arg);