~ubuntu-branches/debian/sid/v4l-utils/sid

« back to all changes in this revision

Viewing changes to .pc/allow-disabling-libjpeg.diff/lib/libv4lconvert/libv4lconvert.c

  • Committer: Bazaar Package Importer
  • Author(s): Gregor Jasny
  • Date: 2011-08-07 14:09:04 UTC
  • Revision ID: james.westby@ubuntu.com-20110807140904-9cmi6jsali7jxrwo
Tags: 0.8.5-3
Disable libjpeg for cross compiled 32bit packages (Closes: #636301)
The libjpeg.so shipped by ia32-libs-dev does not match the current
libjpeg-dev header version which leads to broken (M)JPEG support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
#             (C) 2008-2011 Hans de Goede <hdegoede@redhat.com>
 
3
 
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU Lesser General Public License as published by
 
6
# the Free Software Foundation; either version 2.1 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU Lesser General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU Lesser General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 
17
 */
 
18
 
 
19
#include <errno.h>
 
20
#include <string.h>
 
21
#include <stdlib.h>
 
22
#include <unistd.h>
 
23
#include <sys/stat.h>
 
24
#include <sys/types.h>
 
25
#include "libv4lconvert.h"
 
26
#include "libv4lconvert-priv.h"
 
27
#include "libv4lsyscall-priv.h"
 
28
 
 
29
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
 
30
 
 
31
static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
 
32
                unsigned int pixelformat, int index);
 
33
 
 
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 }
 
43
 
 
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 },
 
82
        /* special */
 
83
        { V4L2_PIX_FMT_SE401,            0,      8,      9,     1 },
 
84
        /* grey formats */
 
85
        { V4L2_PIX_FMT_GREY,             8,     20,     20,     0 },
 
86
        { V4L2_PIX_FMT_Y10BPACK,        10,     20,     20,     0 },
 
87
};
 
88
 
 
89
static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = {
 
90
        SUPPORTED_DST_PIXFMTS
 
91
};
 
92
 
 
93
/* List of well known resolutions which we can get by cropping somewhat larger
 
94
   resolutions */
 
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 */
 
98
        { 320, 240 },
 
99
        { 160, 120 },
 
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 */
 
102
        { 352, 288 },
 
103
        { 176, 144 },
 
104
};
 
105
 
 
106
struct v4lconvert_data *v4lconvert_create(int fd)
 
107
{
 
108
        int i, j;
 
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;
 
115
 
 
116
        if (!data) {
 
117
                fprintf(stderr, "libv4lconvert: error: out of memory!\n");
 
118
                return NULL;
 
119
        }
 
120
 
 
121
        data->fd = fd;
 
122
        data->decompress_pid = -1;
 
123
        data->fps = 30;
 
124
 
 
125
        /* Check supported formats */
 
126
        for (i = 0; ; i++) {
 
127
                struct v4l2_fmtdesc fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
 
128
 
 
129
                fmt.index = i;
 
130
 
 
131
                if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FMT, &fmt))
 
132
                        break;
 
133
 
 
134
                for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++)
 
135
                        if (fmt.pixelformat == supported_src_pixfmts[j].fmt)
 
136
                                break;
 
137
 
 
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;
 
143
                } else
 
144
                        always_needs_conversion = 0;
 
145
        }
 
146
 
 
147
        data->no_formats = i;
 
148
 
 
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;
 
153
 
 
154
                if ((cap.capabilities & 0xff) & ~V4L2_CAP_VIDEO_CAPTURE)
 
155
                        always_needs_conversion = 0;
 
156
        }
 
157
 
 
158
        data->control = v4lcontrol_create(fd, always_needs_conversion);
 
159
        if (!data->control) {
 
160
                free(data);
 
161
                return NULL;
 
162
        }
 
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;
 
167
 
 
168
        data->processing = v4lprocessing_create(fd, data->control);
 
169
        if (!data->processing) {
 
170
                v4lcontrol_destroy(data->control);
 
171
                free(data);
 
172
                return NULL;
 
173
        }
 
174
 
 
175
        return data;
 
176
}
 
177
 
 
178
void v4lconvert_destroy(struct v4lconvert_data *data)
 
179
{
 
180
        v4lprocessing_destroy(data->processing);
 
181
        v4lcontrol_destroy(data->control);
 
182
        if (data->tinyjpeg) {
 
183
                unsigned char *comps[3] = { NULL, NULL, NULL };
 
184
 
 
185
                tinyjpeg_set_components(data->tinyjpeg, comps, 3);
 
186
                tinyjpeg_free(data->tinyjpeg);
 
187
        }
 
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);
 
197
        free(data);
 
198
}
 
199
 
 
200
int v4lconvert_supported_dst_format(unsigned int pixelformat)
 
201
{
 
202
        int i;
 
203
 
 
204
        for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
 
205
                if (supported_dst_pixfmts[i].fmt == pixelformat)
 
206
                        break;
 
207
 
 
208
        return i != ARRAY_SIZE(supported_dst_pixfmts);
 
209
}
 
210
 
 
211
int v4lconvert_supported_dst_fmt_only(struct v4lconvert_data *data)
 
212
{
 
213
        return v4lcontrol_needs_conversion(data->control) &&
 
214
                data->supported_src_formats;
 
215
}
 
216
 
 
217
/* See libv4lconvert.h for description of in / out parameters */
 
218
int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
 
219
{
 
220
        int i, no_faked_fmts = 0;
 
221
        unsigned int faked_fmts[ARRAY_SIZE(supported_dst_pixfmts)];
 
222
 
 
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);
 
227
 
 
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;
 
232
                        no_faked_fmts++;
 
233
                }
 
234
 
 
235
        if (!v4lconvert_supported_dst_fmt_only(data))
 
236
                i = fmt->index - data->no_formats;
 
237
        else
 
238
                i = fmt->index;
 
239
 
 
240
        if (i >= no_faked_fmts) {
 
241
                errno = EINVAL;
 
242
                return -1;
 
243
        }
 
244
 
 
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));
 
253
 
 
254
        return 0;
 
255
}
 
256
 
 
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.
 
260
   
 
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.
 
268
   
 
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)
 
274
{
 
275
        int needed, rank = 0;
 
276
 
 
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;
 
281
                break;
 
282
        case V4L2_PIX_FMT_YUV420:
 
283
        case V4L2_PIX_FMT_YVU420:
 
284
                rank = supported_src_pixfmts[src_index].yuv_rank;
 
285
                break;
 
286
        }
 
287
 
 
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)
 
291
                rank--;
 
292
 
 
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)
 
297
                rank += 10;
 
298
#if 0
 
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);
 
305
#endif
 
306
        return rank;
 
307
}
 
308
 
 
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)
 
315
{
 
316
        int i, rank;
 
317
        unsigned int closest_fmt_size_diff = -1;
 
318
        int best_framesize = 0;/* Just use the first format if no small enough one */
 
319
        int best_format = 0;
 
320
        int best_rank = 100;
 
321
 
 
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;
 
331
 
 
332
                        if (size_diff < closest_fmt_size_diff) {
 
333
                                closest_fmt_size_diff = size_diff;
 
334
                                best_framesize = i;
 
335
                        }
 
336
                }
 
337
        }
 
338
 
 
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)))
 
342
                        continue;
 
343
 
 
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) {
 
351
                        best_rank = rank;
 
352
                        best_format = supported_src_pixfmts[i].fmt;
 
353
                }
 
354
        }
 
355
 
 
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;
 
365
 
 
366
        *src_fmt = *dest_fmt;
 
367
        src_fmt->fmt.pix.pixelformat = best_format;
 
368
 
 
369
        return 0;
 
370
}
 
371
 
 
372
static int v4lconvert_do_try_format(struct v4lconvert_data *data,
 
373
                struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
 
374
{
 
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 };
 
379
 
 
380
        if (data->flags & V4LCONVERT_IS_UVC)
 
381
                return v4lconvert_do_try_format_uvc(data, dest_fmt, src_fmt);
 
382
 
 
383
        for (i = 0; i < ARRAY_SIZE(supported_src_pixfmts); i++) {
 
384
                /* is this format supported? */
 
385
                if (!(data->supported_src_formats & (1 << i)))
 
386
                        continue;
 
387
 
 
388
                try_fmt = *dest_fmt;
 
389
                try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt;
 
390
                if (SYS_IOCTL(data->fd, VIDIOC_TRY_FMT, &try_fmt))
 
391
                        continue;
 
392
 
 
393
                if (try_fmt.fmt.pix.pixelformat !=
 
394
                    supported_src_pixfmts[i].fmt)
 
395
                        continue;
 
396
 
 
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;
 
404
 
 
405
                rank = v4lconvert_get_rank(data, i,
 
406
                                           try_fmt.fmt.pix.width,
 
407
                                           try_fmt.fmt.pix.height,
 
408
                                           desired_pixfmt);
 
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;
 
413
                        best_rank = rank;
 
414
                }
 
415
        }
 
416
 
 
417
        if (closest_fmt.type == 0)
 
418
                return -1;
 
419
 
 
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;
 
424
 
 
425
        return 0;
 
426
}
 
427
 
 
428
void v4lconvert_fixup_fmt(struct v4l2_format *fmt)
 
429
{
 
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;
 
435
                break;
 
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;
 
440
                break;
 
441
        }
 
442
}
 
443
 
 
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)
 
447
{
 
448
        int i, result;
 
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;
 
452
 
 
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;
 
457
 
 
458
        try_dest = *dest_fmt;
 
459
 
 
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);
 
465
                if (src_fmt)
 
466
                        *src_fmt = *dest_fmt;
 
467
                return result;
 
468
        }
 
469
 
 
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);
 
480
                if (result == 0 &&
 
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) {
 
485
                        /* Success! */
 
486
                        try2_dest.fmt.pix.width = desired_width;
 
487
                        try2_dest.fmt.pix.height = desired_height;
 
488
                        try_dest = try2_dest;
 
489
                        try_src = try2_src;
 
490
                }
 
491
        }
 
492
 
 
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;
 
503
 
 
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);
 
509
                                if (result == 0 &&
 
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))) {
 
525
                                        /* Success! */
 
526
                                        try2_dest.fmt.pix.width = desired_width;
 
527
                                        try2_dest.fmt.pix.height = desired_height;
 
528
                                        try_dest = try2_dest;
 
529
                                        try_src = try2_src;
 
530
                                }
 
531
                                break;
 
532
                        }
 
533
                }
 
534
        }
 
535
 
 
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;
 
543
 
 
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);
 
549
 
 
550
        *dest_fmt = try_dest;
 
551
        if (src_fmt)
 
552
                *src_fmt = try_src;
 
553
 
 
554
        return 0;
 
555
}
 
556
 
 
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 */
 
561
{
 
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)))
 
567
                return 1;
 
568
 
 
569
        return 0;
 
570
}
 
571
 
 
572
static int v4lconvert_processing_needs_double_conversion(
 
573
                unsigned int src_pix_fmt, unsigned int dest_pix_fmt)
 
574
{
 
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:
 
589
                return 0;
 
590
        }
 
591
        switch (dest_pix_fmt) {
 
592
        case V4L2_PIX_FMT_RGB24:
 
593
        case V4L2_PIX_FMT_BGR24:
 
594
                return 0;
 
595
        }
 
596
 
 
597
        return 1;
 
598
}
 
599
 
 
600
unsigned char *v4lconvert_alloc_buffer(int needed,
 
601
                unsigned char **buf, int *buf_size)
 
602
{
 
603
        if (*buf_size < needed) {
 
604
                free(*buf);
 
605
                *buf = malloc(needed);
 
606
                if (*buf == NULL) {
 
607
                        *buf_size = 0;
 
608
                        return NULL;
 
609
                }
 
610
                *buf_size = needed;
 
611
        }
 
612
        return *buf;
 
613
}
 
614
 
 
615
int v4lconvert_oom_error(struct v4lconvert_data *data)
 
616
{
 
617
        V4LCONVERT_ERR("could not allocate memory\n");
 
618
        errno = ENOMEM;
 
619
        return -1;
 
620
}
 
621
 
 
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)
 
625
{
 
626
        int result = 0;
 
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;
 
630
 
 
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,
 
637
                                                        src, src_size, dest,
 
638
                                                        fmt, dest_pix_fmt, 0);
 
639
                } else {
 
640
                        result = v4lconvert_decode_jpeg_libjpeg(data,
 
641
                                                        src, src_size, dest,
 
642
                                                        fmt, dest_pix_fmt);
 
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,
 
649
                                                        src, src_size, dest,
 
650
                                                        fmt, dest_pix_fmt, 0);
 
651
                        }
 
652
                }
 
653
                break;
 
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);
 
658
                break;
 
659
        case V4L2_PIX_FMT_JPGL:
 
660
                result = v4lconvert_decode_jpgl(src, src_size, dest_pix_fmt,
 
661
                                                dest, width, height);
 
662
                break;
 
663
 
 
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: {
 
675
                unsigned char *d;
 
676
                int d_size;
 
677
                int yvu = 0;
 
678
 
 
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);
 
683
                        if (!d)
 
684
                                return v4lconvert_oom_error(data);
 
685
                        d_size = width * height * 3 / 2;
 
686
                } else {
 
687
                        d = dest;
 
688
                        d_size = dest_size;
 
689
                }
 
690
 
 
691
                if (dest_pix_fmt == V4L2_PIX_FMT_YVU420)
 
692
                        yvu = 1;
 
693
 
 
694
                switch (src_pix_fmt) {
 
695
                case V4L2_PIX_FMT_SPCA501:
 
696
                        v4lconvert_spca501_to_yuv420(src, d, width, height, yvu);
 
697
                        break;
 
698
                case V4L2_PIX_FMT_SPCA505:
 
699
                        v4lconvert_spca505_to_yuv420(src, d, width, height, yvu);
 
700
                        break;
 
701
                case V4L2_PIX_FMT_SPCA508:
 
702
                        v4lconvert_spca508_to_yuv420(src, d, width, height, yvu);
 
703
                        break;
 
704
                case V4L2_PIX_FMT_CIT_YYVYUY:
 
705
                        v4lconvert_cit_yyvyuy_to_yuv420(src, d, width, height, yvu);
 
706
                        break;
 
707
                case V4L2_PIX_FMT_KONICA420:
 
708
                        v4lconvert_konica_yuv420_to_yuv420(src, d, width, height, yvu);
 
709
                        break;
 
710
                case V4L2_PIX_FMT_M420:
 
711
                        v4lconvert_m420_to_yuv420(src, d, width, height, yvu);
 
712
                        break;
 
713
                case V4L2_PIX_FMT_SN9C20X_I420:
 
714
                        v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu);
 
715
                        break;
 
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 */
 
720
                                errno = EAGAIN;
 
721
                                return -1;
 
722
                        }
 
723
                        break;
 
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 */
 
728
                                errno = EAGAIN;
 
729
                                return -1;
 
730
                        }
 
731
                        break;
 
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 */
 
736
                                errno = EAGAIN;
 
737
                                return -1;
 
738
                        }
 
739
                        break;
 
740
                }
 
741
 
 
742
                switch (dest_pix_fmt) {
 
743
                case V4L2_PIX_FMT_RGB24:
 
744
                        v4lconvert_yuv420_to_rgb24(data->convert_pixfmt_buf, dest, width,
 
745
                                        height, yvu);
 
746
                        break;
 
747
                case V4L2_PIX_FMT_BGR24:
 
748
                        v4lconvert_yuv420_to_bgr24(data->convert_pixfmt_buf, dest, width,
 
749
                                        height, yvu);
 
750
                        break;
 
751
                }
 
752
                break;
 
753
        }
 
754
 
 
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);
 
760
                        break;
 
761
                case V4L2_PIX_FMT_BGR24:
 
762
                        v4lconvert_hm12_to_bgr24(src, dest, width, height);
 
763
                        break;
 
764
                case V4L2_PIX_FMT_YUV420:
 
765
                        v4lconvert_hm12_to_yuv420(src, dest, width, height, 0);
 
766
                        break;
 
767
                case V4L2_PIX_FMT_YVU420:
 
768
                        v4lconvert_hm12_to_yuv420(src, dest, width, height, 1);
 
769
                        break;
 
770
                }
 
771
                break;
 
772
 
 
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;
 
783
 
 
784
                tmpbuf = v4lconvert_alloc_buffer(width * height,
 
785
                                &data->convert_pixfmt_buf, &data->convert_pixfmt_buf_size);
 
786
                if (!tmpbuf)
 
787
                        return v4lconvert_oom_error(data);
 
788
 
 
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;
 
793
                        break;
 
794
                case V4L2_PIX_FMT_SN9C10X:
 
795
                        v4lconvert_decode_sn9c10x(src, tmpbuf, width, height);
 
796
                        tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
 
797
                        break;
 
798
                case V4L2_PIX_FMT_PAC207:
 
799
                        if (v4lconvert_decode_pac207(data, src, src_size, tmpbuf,
 
800
                                                width, height)) {
 
801
                                /* Corrupt frame, better get another one */
 
802
                                errno = EAGAIN;
 
803
                                return -1;
 
804
                        }
 
805
                        tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
 
806
                        break;
 
807
                case V4L2_PIX_FMT_MR97310A:
 
808
                        if (v4lconvert_decode_mr97310a(data, src, src_size, tmpbuf,
 
809
                                                width, height)) {
 
810
                                /* Corrupt frame, better get another one */
 
811
                                errno = EAGAIN;
 
812
                                return -1;
 
813
                        }
 
814
                        tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
 
815
                        break;
 
816
                case V4L2_PIX_FMT_SN9C2028:
 
817
                        v4lconvert_decode_sn9c2028(src, tmpbuf, width, height);
 
818
                        tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
 
819
                        break;
 
820
                case V4L2_PIX_FMT_SQ905C:
 
821
                        v4lconvert_decode_sq905c(src, tmpbuf, width, height);
 
822
                        tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
 
823
                        break;
 
824
                case V4L2_PIX_FMT_STV0680:
 
825
                        v4lconvert_decode_stv0680(src, tmpbuf, width, height);
 
826
                        tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
 
827
                        break;
 
828
                }
 
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;
 
836
                src = tmpbuf;
 
837
                src_size = width * height;
 
838
                /* fall through */
 
839
        }
 
840
 
 
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);
 
849
                        break;
 
850
                case V4L2_PIX_FMT_BGR24:
 
851
                        v4lconvert_bayer_to_bgr24(src, dest, width, height, src_pix_fmt);
 
852
                        break;
 
853
                case V4L2_PIX_FMT_YUV420:
 
854
                        v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 0);
 
855
                        break;
 
856
                case V4L2_PIX_FMT_YVU420:
 
857
                        v4lconvert_bayer_to_yuv420(src, dest, width, height, src_pix_fmt, 1);
 
858
                        break;
 
859
                }
 
860
                if (src_size < (width * height)) {
 
861
                        V4LCONVERT_ERR("short raw bayer data frame\n");
 
862
                        errno = EPIPE;
 
863
                        result = -1;
 
864
                }
 
865
                break;
 
866
 
 
867
        case V4L2_PIX_FMT_SE401: {
 
868
                unsigned char *d = NULL;
 
869
 
 
870
                switch (dest_pix_fmt) {
 
871
                case V4L2_PIX_FMT_RGB24:
 
872
                        d = dest;
 
873
                        break;
 
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);
 
880
                        if (!d)
 
881
                                return v4lconvert_oom_error(data);
 
882
 
 
883
                        fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
 
884
                        v4lconvert_fixup_fmt(fmt);
 
885
                        break;
 
886
                }
 
887
 
 
888
                result = v4lconvert_se401_to_rgb24(data, src, src_size, d,
 
889
                                                   width, height);
 
890
                switch (dest_pix_fmt) {
 
891
                case V4L2_PIX_FMT_BGR24:
 
892
                        v4lconvert_swap_rgb(d, dest, width, height);
 
893
                        break;
 
894
                case V4L2_PIX_FMT_YUV420:
 
895
                        v4lconvert_rgb24_to_yuv420(d, dest, fmt, 0, 0);
 
896
                        break;
 
897
                case V4L2_PIX_FMT_YVU420:
 
898
                        v4lconvert_rgb24_to_yuv420(d, dest, fmt, 0, 1);
 
899
                        break;
 
900
                }
 
901
                break;
 
902
        }
 
903
 
 
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);
 
909
                        break;
 
910
                case V4L2_PIX_FMT_YUV420:
 
911
                case V4L2_PIX_FMT_YVU420:
 
912
                        v4lconvert_grey_to_yuv420(src, dest, fmt);
 
913
                        break;
 
914
                }
 
915
                if (src_size < (width * height)) {
 
916
                        V4LCONVERT_ERR("short grey data frame\n");
 
917
                        errno = EPIPE;
 
918
                        result = -1;
 
919
                }
 
920
                break;
 
921
 
 
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,
 
927
                                                          width, height);
 
928
                        break;
 
929
                case V4L2_PIX_FMT_YUV420:
 
930
                case V4L2_PIX_FMT_YVU420:
 
931
                        result = v4lconvert_y10b_to_yuv420(data, src, dest,
 
932
                                                           width, height);
 
933
                        break;
 
934
                }
 
935
                if (result == 0 && src_size < (width * height * 10 / 8)) {
 
936
                        V4LCONVERT_ERR("short y10b data frame\n");
 
937
                        errno = EPIPE;
 
938
                        result = -1;
 
939
                }
 
940
                break;
 
941
 
 
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);
 
946
                        break;
 
947
                case V4L2_PIX_FMT_BGR24:
 
948
                        v4lconvert_rgb565_to_bgr24(src, dest, width, height);
 
949
                        break;
 
950
                case V4L2_PIX_FMT_YUV420:
 
951
                        v4lconvert_rgb565_to_yuv420(src, dest, fmt, 0);
 
952
                        break;
 
953
                case V4L2_PIX_FMT_YVU420:
 
954
                        v4lconvert_rgb565_to_yuv420(src, dest, fmt, 1);
 
955
                        break;
 
956
                }
 
957
                if (src_size < (width * height * 2)) {
 
958
                        V4LCONVERT_ERR("short rgb565 data frame\n");
 
959
                        errno = EPIPE;
 
960
                        result = -1;
 
961
                }
 
962
                break;
 
963
 
 
964
        case V4L2_PIX_FMT_RGB24:
 
965
                switch (dest_pix_fmt) {
 
966
                case V4L2_PIX_FMT_RGB24:
 
967
                        memcpy(dest, src, width * height * 3);
 
968
                        break;
 
969
                case V4L2_PIX_FMT_BGR24:
 
970
                        v4lconvert_swap_rgb(src, dest, width, height);
 
971
                        break;
 
972
                case V4L2_PIX_FMT_YUV420:
 
973
                        v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 0);
 
974
                        break;
 
975
                case V4L2_PIX_FMT_YVU420:
 
976
                        v4lconvert_rgb24_to_yuv420(src, dest, fmt, 0, 1);
 
977
                        break;
 
978
                }
 
979
                if (src_size < (width * height * 3)) {
 
980
                        V4LCONVERT_ERR("short rgb24 data frame\n");
 
981
                        errno = EPIPE;
 
982
                        result = -1;
 
983
                }
 
984
                break;
 
985
 
 
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);
 
990
                        break;
 
991
                case V4L2_PIX_FMT_BGR24:
 
992
                        memcpy(dest, src, width * height * 3);
 
993
                        break;
 
994
                case V4L2_PIX_FMT_YUV420:
 
995
                        v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 0);
 
996
                        break;
 
997
                case V4L2_PIX_FMT_YVU420:
 
998
                        v4lconvert_rgb24_to_yuv420(src, dest, fmt, 1, 1);
 
999
                        break;
 
1000
                }
 
1001
                if (src_size < (width * height * 3)) {
 
1002
                        V4LCONVERT_ERR("short bgr24 data frame\n");
 
1003
                        errno = EPIPE;
 
1004
                        result = -1;
 
1005
                }
 
1006
                break;
 
1007
 
 
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,
 
1012
                                        height, 0);
 
1013
                        break;
 
1014
                case V4L2_PIX_FMT_BGR24:
 
1015
                        v4lconvert_yuv420_to_bgr24(src, dest, width,
 
1016
                                        height, 0);
 
1017
                        break;
 
1018
                case V4L2_PIX_FMT_YUV420:
 
1019
                        memcpy(dest, src, width * height * 3 / 2);
 
1020
                        break;
 
1021
                case V4L2_PIX_FMT_YVU420:
 
1022
                        v4lconvert_swap_uv(src, dest, fmt);
 
1023
                        break;
 
1024
                }
 
1025
                if (src_size < (width * height * 3 / 2)) {
 
1026
                        V4LCONVERT_ERR("short yuv420 data frame\n");
 
1027
                        errno = EPIPE;
 
1028
                        result = -1;
 
1029
                }
 
1030
                break;
 
1031
 
 
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,
 
1036
                                        height, 1);
 
1037
                        break;
 
1038
                case V4L2_PIX_FMT_BGR24:
 
1039
                        v4lconvert_yuv420_to_bgr24(src, dest, width,
 
1040
                                        height, 1);
 
1041
                        break;
 
1042
                case V4L2_PIX_FMT_YUV420:
 
1043
                        v4lconvert_swap_uv(src, dest, fmt);
 
1044
                        break;
 
1045
                case V4L2_PIX_FMT_YVU420:
 
1046
                        memcpy(dest, src, width * height * 3 / 2);
 
1047
                        break;
 
1048
                }
 
1049
                if (src_size < (width * height * 3 / 2)) {
 
1050
                        V4LCONVERT_ERR("short yvu420 data frame\n");
 
1051
                        errno = EPIPE;
 
1052
                        result = -1;
 
1053
                }
 
1054
                break;
 
1055
 
 
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);
 
1060
                        break;
 
1061
                case V4L2_PIX_FMT_BGR24:
 
1062
                        v4lconvert_yuyv_to_bgr24(src, dest, width, height);
 
1063
                        break;
 
1064
                case V4L2_PIX_FMT_YUV420:
 
1065
                        v4lconvert_yuyv_to_yuv420(src, dest, width, height, 0);
 
1066
                        break;
 
1067
                case V4L2_PIX_FMT_YVU420:
 
1068
                        v4lconvert_yuyv_to_yuv420(src, dest, width, height, 1);
 
1069
                        break;
 
1070
                }
 
1071
                if (src_size < (width * height * 2)) {
 
1072
                        V4LCONVERT_ERR("short yuyv data frame\n");
 
1073
                        errno = EPIPE;
 
1074
                        result = -1;
 
1075
                }
 
1076
                break;
 
1077
 
 
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);
 
1082
                        break;
 
1083
                case V4L2_PIX_FMT_BGR24:
 
1084
                        v4lconvert_yvyu_to_bgr24(src, dest, width, height);
 
1085
                        break;
 
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);
 
1090
                        break;
 
1091
                case V4L2_PIX_FMT_YVU420:
 
1092
                        v4lconvert_yuyv_to_yuv420(src, dest, width, height, 0);
 
1093
                        break;
 
1094
                }
 
1095
                if (src_size < (width * height * 2)) {
 
1096
                        V4LCONVERT_ERR("short yvyu data frame\n");
 
1097
                        errno = EPIPE;
 
1098
                        result = -1;
 
1099
                }
 
1100
                break;
 
1101
 
 
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);
 
1106
                        break;
 
1107
                case V4L2_PIX_FMT_BGR24:
 
1108
                        v4lconvert_uyvy_to_bgr24(src, dest, width, height);
 
1109
                        break;
 
1110
                case V4L2_PIX_FMT_YUV420:
 
1111
                        v4lconvert_uyvy_to_yuv420(src, dest, width, height, 0);
 
1112
                        break;
 
1113
                case V4L2_PIX_FMT_YVU420:
 
1114
                        v4lconvert_uyvy_to_yuv420(src, dest, width, height, 1);
 
1115
                        break;
 
1116
                }
 
1117
                if (src_size < (width * height * 2)) {
 
1118
                        V4LCONVERT_ERR("short uyvy data frame\n");
 
1119
                        errno = EPIPE;
 
1120
                        result = -1;
 
1121
                }
 
1122
                break;
 
1123
 
 
1124
        default:
 
1125
                V4LCONVERT_ERR("Unknown src format in conversion\n");
 
1126
                errno = EINVAL;
 
1127
                return -1;
 
1128
        }
 
1129
 
 
1130
        fmt->fmt.pix.pixelformat = dest_pix_fmt;
 
1131
        v4lconvert_fixup_fmt(fmt);
 
1132
 
 
1133
        return result;
 
1134
}
 
1135
 
 
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)
 
1140
{
 
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;
 
1152
 
 
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;
 
1159
 
 
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);
 
1168
                return to_copy;
 
1169
        }
 
1170
 
 
1171
        /* When field is V4L2_FIELD_ALTERNATE, each buffer only contains half the
 
1172
           lines */
 
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;
 
1176
        }
 
1177
 
 
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;
 
1184
                break;
 
1185
        case V4L2_PIX_FMT_YUV420:
 
1186
        case V4L2_PIX_FMT_YVU420:
 
1187
                dest_needed =
 
1188
                        my_dest_fmt.fmt.pix.width * my_dest_fmt.fmt.pix.height * 3 / 2;
 
1189
                temp_needed =
 
1190
                        my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3 / 2;
 
1191
                break;
 
1192
        default:
 
1193
                V4LCONVERT_ERR("Unknown dest format in conversion\n");
 
1194
                errno = EINVAL;
 
1195
                return -1;
 
1196
        }
 
1197
 
 
1198
        if (dest_size < dest_needed) {
 
1199
                V4LCONVERT_ERR("destination buffer too small (%d < %d)\n",
 
1200
                                dest_size, dest_needed);
 
1201
                errno = EFAULT;
 
1202
                return -1;
 
1203
        }
 
1204
 
 
1205
 
 
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))
 
1211
                convert = 2;
 
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
 
1217
                    source to dest */
 
1218
                 (!rotate90 && !hflip && !vflip && !crop))
 
1219
                convert = 1;
 
1220
 
 
1221
        /* convert_pixfmt (only if convert == 2) -> processing -> convert_pixfmt ->
 
1222
           rotate -> flip -> crop, all steps are optional */
 
1223
        if (convert == 2) {
 
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);
 
1227
                if (!convert1_dest)
 
1228
                        return v4lconvert_oom_error(data);
 
1229
 
 
1230
                convert1_dest_size =
 
1231
                        my_src_fmt.fmt.pix.width * my_src_fmt.fmt.pix.height * 3;
 
1232
                convert2_src = convert1_dest;
 
1233
        }
 
1234
 
 
1235
        if (convert && (rotate90 || hflip || vflip || crop)) {
 
1236
                convert2_dest = v4lconvert_alloc_buffer(temp_needed,
 
1237
                                &data->convert2_buf, &data->convert2_buf_size);
 
1238
                if (!convert2_dest)
 
1239
                        return v4lconvert_oom_error(data);
 
1240
 
 
1241
                convert2_dest_size = temp_needed;
 
1242
                rotate90_src = flip_src = crop_src = convert2_dest;
 
1243
        }
 
1244
 
 
1245
        if (rotate90 && (hflip || vflip || crop)) {
 
1246
                rotate90_dest = v4lconvert_alloc_buffer(temp_needed,
 
1247
                                &data->rotate90_buf, &data->rotate90_buf_size);
 
1248
                if (!rotate90_dest)
 
1249
                        return v4lconvert_oom_error(data);
 
1250
 
 
1251
                flip_src = crop_src = rotate90_dest;
 
1252
        }
 
1253
 
 
1254
        if ((vflip || hflip) && crop) {
 
1255
                flip_dest = v4lconvert_alloc_buffer(temp_needed, &data->flip_buf,
 
1256
                                &data->flip_buf_size);
 
1257
                if (!flip_dest)
 
1258
                        return v4lconvert_oom_error(data);
 
1259
 
 
1260
                crop_src = flip_dest;
 
1261
        }
 
1262
 
 
1263
        /* Done setting sources / dest and allocating intermediate buffers,
 
1264
           real conversion / processing / ... starts here. */
 
1265
        if (convert == 2) {
 
1266
                res = v4lconvert_convert_pixfmt(data, src, src_size,
 
1267
                                convert1_dest, convert1_dest_size,
 
1268
                                &my_src_fmt,
 
1269
                                V4L2_PIX_FMT_RGB24);
 
1270
                if (res)
 
1271
                        return res;
 
1272
 
 
1273
                src_size = my_src_fmt.fmt.pix.sizeimage;
 
1274
        }
 
1275
 
 
1276
        if (processing)
 
1277
                v4lprocessing_processing(data->processing, convert2_src, &my_src_fmt);
 
1278
 
 
1279
        if (convert) {
 
1280
                res = v4lconvert_convert_pixfmt(data, convert2_src, src_size,
 
1281
                                convert2_dest, convert2_dest_size,
 
1282
                                &my_src_fmt,
 
1283
                                my_dest_fmt.fmt.pix.pixelformat);
 
1284
                if (res)
 
1285
                        return res;
 
1286
 
 
1287
                src_size = my_src_fmt.fmt.pix.sizeimage;
 
1288
 
 
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. */
 
1292
                if (processing)
 
1293
                        v4lprocessing_processing(data->processing, convert2_dest, &my_src_fmt);
 
1294
        }
 
1295
 
 
1296
        if (rotate90)
 
1297
                v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt);
 
1298
 
 
1299
        if (hflip || vflip)
 
1300
                v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, hflip, vflip);
 
1301
 
 
1302
        if (crop)
 
1303
                v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt);
 
1304
 
 
1305
        return dest_needed;
 
1306
}
 
1307
 
 
1308
const char *v4lconvert_get_error_message(struct v4lconvert_data *data)
 
1309
{
 
1310
        return data->error_msg;
 
1311
}
 
1312
 
 
1313
static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
 
1314
                unsigned int pixelformat, int index)
 
1315
{
 
1316
        int i, j, match;
 
1317
        struct v4l2_frmsizeenum frmsize = { .pixel_format = pixelformat };
 
1318
 
 
1319
        for (i = 0; ; i++) {
 
1320
                frmsize.index = i;
 
1321
                if (SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize))
 
1322
                        break;
 
1323
 
 
1324
                /* We got a framesize, check we don't have the same one already */
 
1325
                match = 0;
 
1326
                for (j = 0; j < data->no_framesizes; j++) {
 
1327
                        if (frmsize.type != data->framesizes[j].type)
 
1328
                                continue;
 
1329
 
 
1330
                        switch (frmsize.type) {
 
1331
                        case V4L2_FRMSIZE_TYPE_DISCRETE:
 
1332
                                if (!memcmp(&frmsize.discrete, &data->framesizes[j].discrete,
 
1333
                                                        sizeof(frmsize.discrete)))
 
1334
                                        match = 1;
 
1335
                                break;
 
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)))
 
1340
                                        match = 1;
 
1341
                                break;
 
1342
                        }
 
1343
                        if (match)
 
1344
                                break;
 
1345
                }
 
1346
                /* Add this framesize if it is not already in our list */
 
1347
                if (!match) {
 
1348
                        if (data->no_framesizes == V4LCONVERT_MAX_FRAMESIZES) {
 
1349
                                fprintf(stderr, "libv4lconvert: warning more framesizes then I can handle!\n");
 
1350
                                return;
 
1351
                        }
 
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;
 
1356
 
 
1357
                        switch (frmsize.type) {
 
1358
                        case V4L2_FRMSIZE_TYPE_DISCRETE:
 
1359
                                data->framesizes[data->no_framesizes].discrete = frmsize.discrete;
 
1360
                                break;
 
1361
                        case V4L2_FRMSIZE_TYPE_CONTINUOUS:
 
1362
                        case V4L2_FRMSIZE_TYPE_STEPWISE:
 
1363
                                data->framesizes[data->no_framesizes].stepwise = frmsize.stepwise;
 
1364
                                break;
 
1365
                        }
 
1366
                        data->no_framesizes++;
 
1367
                } else {
 
1368
                        data->framesizes[j].pixel_format |= 1 << index;
 
1369
                }
 
1370
        }
 
1371
}
 
1372
 
 
1373
int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
 
1374
                struct v4l2_frmsizeenum *frmsize)
 
1375
{
 
1376
        if (!v4lconvert_supported_dst_format(frmsize->pixel_format)) {
 
1377
                if (v4lconvert_supported_dst_fmt_only(data)) {
 
1378
                        errno = EINVAL;
 
1379
                        return -1;
 
1380
                }
 
1381
                return SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize);
 
1382
        }
 
1383
 
 
1384
        if (frmsize->index >= data->no_framesizes) {
 
1385
                errno = EINVAL;
 
1386
                return -1;
 
1387
        }
 
1388
 
 
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;
 
1396
                break;
 
1397
        case V4L2_FRMSIZE_TYPE_CONTINUOUS:
 
1398
        case V4L2_FRMSIZE_TYPE_STEPWISE:
 
1399
                frmsize->stepwise = data->framesizes[frmsize->index].stepwise;
 
1400
                break;
 
1401
        }
 
1402
 
 
1403
        return 0;
 
1404
}
 
1405
 
 
1406
int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
 
1407
                struct v4l2_frmivalenum *frmival)
 
1408
{
 
1409
        int res;
 
1410
        struct v4l2_format src_fmt, dest_fmt;
 
1411
 
 
1412
        if (!v4lconvert_supported_dst_format(frmival->pixel_format)) {
 
1413
                if (v4lconvert_supported_dst_fmt_only(data)) {
 
1414
                        errno = EINVAL;
 
1415
                        return -1;
 
1416
                }
 
1417
                res = SYS_IOCTL(data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
 
1418
                if (res)
 
1419
                        V4LCONVERT_ERR("%s\n", strerror(errno));
 
1420
                return res;
 
1421
        }
 
1422
 
 
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);
 
1430
        if (res) {
 
1431
                V4LCONVERT_ERR("trying format: %s\n", strerror(errno));
 
1432
                return res;
 
1433
        }
 
1434
 
 
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;
 
1441
 
 
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);
 
1454
                errno = EINVAL;
 
1455
                return -1;
 
1456
        }
 
1457
 
 
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);
 
1463
        if (res) {
 
1464
                int dest_pixfmt = dest_fmt.fmt.pix.pixelformat;
 
1465
                int src_pixfmt  = src_fmt.fmt.pix.pixelformat;
 
1466
 
 
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",
 
1469
                                frmival->index,
 
1470
                                dest_pixfmt & 0xff,
 
1471
                                (dest_pixfmt >> 8) & 0xff,
 
1472
                                (dest_pixfmt >> 16) & 0xff,
 
1473
                                dest_pixfmt >> 24,
 
1474
                                dest_fmt.fmt.pix.width , dest_fmt.fmt.pix.height,
 
1475
                                src_pixfmt & 0xff,
 
1476
                                (src_pixfmt >> 8) & 0xff,
 
1477
                                (src_pixfmt >> 16) & 0xff,
 
1478
                                src_pixfmt >> 24,
 
1479
                                src_fmt.fmt.pix.width, src_fmt.fmt.pix.height, strerror(errno));
 
1480
        }
 
1481
 
 
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;
 
1486
 
 
1487
        return res;
 
1488
}
 
1489
 
 
1490
int v4lconvert_vidioc_queryctrl(struct v4lconvert_data *data, void *arg)
 
1491
{
 
1492
        return v4lcontrol_vidioc_queryctrl(data->control, arg);
 
1493
}
 
1494
 
 
1495
int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data, void *arg)
 
1496
{
 
1497
        return v4lcontrol_vidioc_g_ctrl(data->control, arg);
 
1498
}
 
1499
 
 
1500
int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data, void *arg)
 
1501
{
 
1502
        return v4lcontrol_vidioc_s_ctrl(data->control, arg);
 
1503
}
 
1504
 
 
1505
int v4lconvert_get_fps(struct v4lconvert_data *data)
 
1506
{
 
1507
        return data->fps;
 
1508
}
 
1509
 
 
1510
void v4lconvert_set_fps(struct v4lconvert_data *data, int fps)
 
1511
{
 
1512
        data->fps = fps;
 
1513
}