2 * @file microdia-decoder.c
3 * @author Nicolas VIVIEN
6 * @brief Decoder for device specific image formats
8 * @note Copyright (C) Nicolas VIVIEN
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include <linux/kernel.h>
30 #include <linux/version.h>
31 #include <linux/errno.h>
32 #include <linux/slab.h>
33 #include <linux/kref.h>
35 #include <linux/usb.h>
36 #include <media/v4l2-common.h>
41 #define MAX(a, b) ((a) > (b) ? (a) : (b))
42 #define MIN(a, b) ((a) < (b) ? (a) : (b))
43 #define CLIP(a, low, high) MAX((low), MIN((high), (a)))
45 void raw6270_2i420(uint8_t *, uint8_t *, int,
46 int, const int, const int);
48 void raw6270_2RGB24(uint8_t *raw
, uint8_t *rgb
, int width
,
49 int height
, const int hflip
,
52 void raw6270_2BGR24(uint8_t *raw
, uint8_t *rgb
, int width
,
53 int height
, const int hflip
,
56 void microdia_getraw(uint8_t *, uint8_t *, int);
58 void microdia_raw2i420(uint8_t *, uint8_t *, int,
59 int, const int, const int);
61 void microdia_raw2bgr24(uint8_t *, uint8_t *, int,
62 int, const int, const int);
64 * @brief Decompress a frame
66 * This function permits to decompress a frame from the video stream.
68 * @param dev Device structure
69 * @param buffer Image data
71 * @returns 0 if all is OK
73 int microdia_decompress(struct usb_microdia
*dev
, struct v4l2_buffer
*buffer
)
90 dev
->flip_detect(dev
);
92 if (dev
->set_hvflip
) {
96 hflip
= dev
->vsettings
.hflip
;
97 vflip
= dev
->vsettings
.vflip
;
100 image
= dev
->queue
.scratch
;
102 data
= dev
->queue
.mem
+ buffer
->m
.offset
;
103 memcpy(image
, data
, MICRODIA_FRAME_SIZE
);
107 width
= dev
->vsettings
.format
.width
;
108 height
= dev
->vsettings
.format
.height
;
110 switch (dev
->vsettings
.format
.pixelformat
) {
111 case V4L2_PIX_FMT_RGB24
:
112 if (dev
->webcam_model
==
113 CAMERA_MODEL(USB_0C45_VID
, USB_6270_PID
) ||
115 CAMERA_MODEL(USB_0C45_VID
, USB_627B_PID
) ||
117 CAMERA_MODEL(USB_0C45_VID
, USB_6288_PID
) ||
119 CAMERA_MODEL(USB_0C45_VID
, USB_62B3_PID
) ||
121 CAMERA_MODEL(USB_0C45_VID
, USB_62BB_PID
) ||
123 CAMERA_MODEL(USB_145F_VID
, USB_013D_PID
)) {
124 raw6270_2RGB24(image
, data
, width
,
125 height
, hflip
, vflip
);
128 case V4L2_PIX_FMT_BGR24
:
129 if (dev
->webcam_model
==
130 CAMERA_MODEL(USB_0C45_VID
, USB_6270_PID
) ||
132 CAMERA_MODEL(USB_0C45_VID
, USB_627B_PID
) ||
134 CAMERA_MODEL(USB_0C45_VID
, USB_6288_PID
) ||
136 CAMERA_MODEL(USB_0C45_VID
, USB_62B3_PID
) ||
138 CAMERA_MODEL(USB_0C45_VID
, USB_62BB_PID
) ||
140 CAMERA_MODEL(USB_145F_VID
, USB_013D_PID
)) {
141 raw6270_2BGR24(image
, data
, width
,
142 height
, hflip
, vflip
);
144 microdia_raw2bgr24(image
, data
, width
,
145 height
, hflip
, vflip
);
148 case V4L2_PIX_FMT_YUV420
:
149 if (dev
->webcam_model
==
150 CAMERA_MODEL(USB_0C45_VID
, USB_6270_PID
) ||
152 CAMERA_MODEL(USB_0C45_VID
, USB_627B_PID
) ||
154 CAMERA_MODEL(USB_0C45_VID
, USB_6288_PID
) ||
156 CAMERA_MODEL(USB_0C45_VID
, USB_62B3_PID
) ||
158 CAMERA_MODEL(USB_0C45_VID
, USB_62BB_PID
) ||
160 CAMERA_MODEL(USB_145F_VID
, USB_013D_PID
)) {
161 raw6270_2i420(image
, data
, width
,
162 height
, hflip
, vflip
);
164 microdia_raw2i420(image
, data
, width
,
165 height
, hflip
, vflip
);
168 case V4L2_PIX_FMT_YUYV
:
173 buffer
->bytesused
= dev
->vsettings
.format
.sizeimage
;
179 * @brief This function permits to get the raw data. (without treatments)
181 * @param bayer Buffer with the bayer data
182 * @param size Length of bayer buffer
184 * @retval raw Buffer with the data from video sensor
186 void microdia_getraw(uint8_t *bayer
, uint8_t *raw
,
188 memcpy(raw
, bayer
, size
);
191 /* Table to translate Y offset to UV offset */
192 static int UVTranslate
[32] = {
203 static int Y_coords_624x
[128][2] = {
204 { 0, 0}, { 1, 0}, { 2, 0}, { 3, 0}, { 4, 0}, { 5, 0}, { 6, 0}, { 7, 0},
205 { 0, 1}, { 1, 1}, { 2, 1}, { 3, 1}, { 4, 1}, { 5, 1}, { 6, 1}, { 7, 1},
206 { 0, 2}, { 1, 2}, { 2, 2}, { 3, 2}, { 4, 2}, { 5, 2}, { 6, 2}, { 7, 2},
207 { 0, 3}, { 1, 3}, { 2, 3}, { 3, 3}, { 4, 3}, { 5, 3}, { 6, 3}, { 7, 3},
209 { 0, 4}, { 1, 4}, { 2, 4}, { 3, 4}, { 4, 4}, { 5, 4}, { 6, 4}, { 7, 4},
210 { 0, 5}, { 1, 5}, { 2, 5}, { 3, 5}, { 4, 5}, { 5, 5}, { 6, 5}, { 7, 5},
211 { 0, 6}, { 1, 6}, { 2, 6}, { 3, 6}, { 4, 6}, { 5, 6}, { 6, 6}, { 7, 6},
212 { 0, 7}, { 1, 7}, { 2, 7}, { 3, 7}, { 4, 7}, { 5, 7}, { 6, 7}, { 7, 7},
214 { 8, 0}, { 9, 0}, {10, 0}, {11, 0}, {12, 0}, {13, 0}, {14, 0}, {15, 0},
215 { 8, 1}, { 9, 1}, {10, 1}, {11, 1}, {12, 1}, {13, 1}, {14, 1}, {15, 1},
216 { 8, 2}, { 9, 2}, {10, 2}, {11, 2}, {12, 2}, {13, 2}, {14, 2}, {15, 2},
217 { 8, 3}, { 9, 3}, {10, 3}, {11, 3}, {12, 3}, {13, 3}, {14, 3}, {15, 3},
219 { 8, 4}, { 9, 4}, {10, 4}, {11, 4}, {12, 4}, {13, 4}, {14, 4}, {15, 4},
220 { 8, 5}, { 9, 5}, {10, 5}, {11, 5}, {12, 5}, {13, 5}, {14, 5}, {15, 5},
221 { 8, 6}, { 9, 6}, {10, 6}, {11, 6}, {12, 6}, {13, 6}, {14, 6}, {15, 6},
222 { 8, 7}, { 9, 7}, {10, 7}, {11, 7}, {12, 7}, {13, 7}, {14, 7}, {15, 7}
227 * @brief This function permits to convert an image from 624x raw format to bgr24
228 * @param raw Buffer with the raw data
229 * @param width Width of image
230 * @param height Height of image
231 * @param hflip Horizontal flip
232 * @param vflip Vertical flip
234 * @retval rgb Buffer with the rgb data
236 void microdia_raw2bgr24(uint8_t *raw
, uint8_t *rgb
,
237 int width
, int height
, const int hflip
,
240 int i
= 0, x
= 0, y
= 0;
241 unsigned char *buf
= raw
;
242 unsigned char *buf3
= rgb
;
244 while (i
< (width
* height
+ (width
* height
) / 2)) {
246 for (tile
= 0; tile
< 4; tile
++) {
249 for (subY
= 0; subY
< 4; subY
++) {
250 for (subX
= 0; subX
< 8; subX
++) {
251 int subI
= i
+ tile
* 32 + 8 * subY
+ subX
;
252 int subU
= i
+ 128 + UVTranslate
[tile
* 8 + 4 * (subY
>> 1) + (subX
>> 1)];
253 int subV
= subU
+ 32;
255 int relX
= x
+ (((tile
== 0) || (tile
== 1)) ? 0 : 8) + subX
; /* tile 0, 1 to into left column*/
256 int relY
= y
+ (((tile
== 0) || (tile
== 2)) ? 0 : 4) + subY
; /* tile 0, 2 go into top row */
261 relY
= height
- relY
;
263 if ((relX
< width
) && (relY
< height
)) {
270 ptr
= buf3
+ relY
* width
* 3 + relX
* 3;
271 *ptr
= CLIP((298 * c
+ 516 * d
+ 128) >> 8, 0, 255);
273 *ptr
= CLIP((298 * c
- 100 * d
- 208 * e
+ 128) >> 8, 0, 255);
275 *ptr
= CLIP((298 * c
+ 409 * e
+ 128) >> 8, 0, 255);
292 * @brief This function permits to convert an image from 624x raw format to i420
293 * @param raw Buffer with the raw data
294 * @param width Width of image
295 * @param height Height of image
296 * @param hflip Horizontal flip
297 * @param vflip Vertical flip
299 * @retval i420 Buffer with the i420 data
301 void microdia_raw2i420(uint8_t *raw
, uint8_t *i420
,
302 int width
, int height
, const int hflip
,
305 int i
= 0, x
= 0, y
= 0, j
, relX
, relY
, x_div2
, y_div2
;
306 unsigned char *buf
= raw
, *ptr
;
307 unsigned char *buf3
= i420
;
308 int view_size
= width
* height
;
309 int view_size_div4
= view_size
>> 2;
310 int image_x_div2
= width
>> 1;
311 int image_y_div2
= height
>> 1;
312 int view_x_div2
= width
>> 1;
314 while (i
< (width
* height
+ (width
* height
) / 2)) {
315 for (j
= 0; j
< 128; j
++) {
316 relX
= x
+ Y_coords_624x
[j
][0];
317 relY
= y
+ Y_coords_624x
[j
][1];
319 relX
= width
- relX
- 1;
321 relY
= height
- relY
- 1;
323 if ((relX
< width
) && (relY
< height
)) {
324 ptr
= buf3
+ relY
* width
+ relX
;
331 for (j
= 0; j
< 32; j
++) {
332 relX
= (x_div2
) + (j
& 0x07);
333 relY
= (y_div2
) + (j
>> 3);
335 relX
= image_x_div2
- relX
- 1;
337 relY
= image_y_div2
- relY
- 1;
339 if ((relX
< width
) && (relY
< height
)) {
340 ptr
= buf3
+ view_size
+
341 relY
* (view_x_div2
) + relX
;
342 *ptr
= buf
[i
+ 128 + j
];
343 ptr
+= view_size_div4
;
344 *ptr
= buf
[i
+ 160 + j
];
360 * @brief This function permits to convert an image from 6270 raw format to i420
361 * @param raw Buffer with the bayer data
362 * @param width Width of image
363 * @param height Height of image
364 * @param hflip Horizontal flip - not implemented
365 * @param vflip Vertical flip - not implemented
367 * @retval i420 Buffer with the i420 data
368 * Format of stream is uvyy,uvyy - repeated 320 times for 640x480
369 * y - repeated 640 times for 640x480
370 * First 1280 bytes is maybe dummy ***FIXME***
372 void raw6270_2i420(uint8_t *raw
, uint8_t *i420
, int width
,
373 int height
, const int hflip
,
376 int i
, j
, YIndex
= 0, UVIndex
= 0;
377 unsigned char *y
, *u
, *v
;
379 /* For fast calculations */
380 int x_div_2
, y_div_2
;
381 /* Skip first 1280 bytes strange dummy bytes */
384 x_div_2
= width
/ 2; /* for fast calculation if x=640 x_div_2=320 */
385 y_div_2
= height
/ 2; /* for fast calculation if y=480 y_div_4=240 */
388 u
= i420
+ width
* height
;
389 v
= i420
+ width
* height
+ (width
>> 1) * (height
>> 1);
393 /* we skipped 1280 bytes, it's almost two lines */
394 for (i
= 0; i
< y_div_2
- 1; i
++) {
395 for (j
= 0; j
< x_div_2
; j
++) {
411 for (j
= 0; j
< width
; j
++) {
420 UVIndex
+= (width
>> 1);
426 * @brief This function permits to convert an image from 6270 rawformat to BGR24
427 * @param raw Buffer with the bayer data
428 * @param width Width of image
429 * @param height Height of image
430 * @param hflip Horizontal flip - not implemented yet
431 * @param vflip Vertical flip - not implemented yet
433 * @retval rgb Buffer with the rgb data
434 * Format of stream is uvyy,uvyy - repeated 320 times for 640x480
435 * y - repeated 640 times for 640x480
436 * First 1280 bytes is maybe dumy ***FIXME***
438 void raw6270_2BGR24(uint8_t *raw
, uint8_t *rgb
, int width
,
439 int height
, const int hflip
,
443 /* Maybe is not necesery to use long variables but I not sure in this moment */
444 long y11
, y12
, y21
, y22
, u
, v
, y
, C
, D
, E
;
445 long ScaleIncX
, ScaleIncY
;
446 long pointerIncX
, pointerIncY
;
452 /* For fast calculations*/
453 int x_div_2
, y_div_2
;
454 /* Skip first 1280 bytes strange dummy bytes */
457 x_div_2
= width
/ 2; /* for fast calculation if x=640 x_div_2=320 */
458 y_div_2
= height
/ 2; /* for fast calculation if y=480 y_div_4=240 */
459 incX
= 3 * width
; /* Incrementation koeficient for next row*/
461 bufY
= raw
+ 2 * width
;
464 // Because I can't use float ratio is multiply by 1000
465 // then 1000 is equal of increment image (X or Y) with 1
467 ScaleIncX
= (1000 * width
) / width
;
468 ScaleIncY
= (1000 * height
) / height
;
471 out_row2
= out_row1
+ incX
;
472 /* we skipped 1280 bytes, it's almost two lines*/
474 for (i
= 0; i
< y_div_2
-1; i
++) {
476 for (j
= 0; j
< x_div_2
; j
++) {
477 pointerIncX
+= ScaleIncX
;
479 u
= (unsigned char)(*bufUVYY
);
482 v
= (unsigned char)(*bufUVYY
);
485 y11
= (unsigned char)(*bufUVYY
);
488 y12
= (unsigned char)(*bufUVYY
);
491 y21
= (unsigned char)(*bufY
);
494 y22
= (unsigned char)(*bufY
);
497 if ((pointerIncX
> 999) && (pointerIncY
> 499)) {
504 *out_row1
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
506 *out_row1
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
508 *out_row1
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
518 *out_row1
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
520 *out_row1
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
522 *out_row1
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
526 // Second row of stream is displayed only
527 // if image is greath than half
529 if (ScaleIncY
> 501) {
536 *out_row2
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
538 *out_row2
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
540 *out_row2
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
549 *out_row2
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
551 *out_row2
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
553 *out_row2
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
559 // this comparation can be optimized and moved in
560 // if((pointerIncX>999)&&(pointerIncY>499))
562 if (pointerIncY
> 499)
565 // Use 2 rows only if
566 // vertical ratio > 0.5 (increment is ratio*1000)
568 if (ScaleIncY
> 501) {
569 out_row1
= out_row1
+ incX
;
570 out_row2
= out_row2
+ incX
;
573 pointerIncY
+= ScaleIncY
;
574 bufUVYY
= bufUVYY
+ width
;
575 bufY
= bufY
+ 2 * width
;
581 * @brief This function permits to convert an image from 6270 rawformat to RGB24
582 * @brief The same function as convert to BGR24 but only B and R is change order
583 * @param raw Buffer with the bayer data
584 * @param width Width of image
585 * @param height Height of image
586 * @param hflip Horizontal flip
587 * @param vflip Vertical flip
589 * @retval rgb Buffer with the rgb data
590 * Format of stream is uvyy,uvyy - repeated 320 times for 640x480
591 * y - repeated 640 times for 640x480
592 * First 1280 bytes is maybe dumy ***FIXME***
594 void raw6270_2RGB24(uint8_t *raw
, uint8_t *rgb
, int width
,
595 int height
, const int hflip
,
599 /* Maybe is not necesery to use long variables but I not sure in this moment */
600 long y11
, y12
, y21
, y22
, u
, v
, y
, C
, D
, E
;
601 long ScaleIncX
, ScaleIncY
;
602 long pointerIncX
, pointerIncY
;
608 /* For fast calculations */
609 int x_div_2
, y_div_2
;
610 /* Skip first 1280 bytes strange dummy bytes */
613 x_div_2
= width
/ 2; /* for fast calculation if x=640 x_div_2=320 */
614 y_div_2
= height
/ 2; /* for fast calculation if y=480 y_div_4=240 */
617 bufY
= raw
+ 2 * width
;
620 // Because I can't use float ratio is multiply by 1000 then
621 // 1000 is equal of increment image (X or Y) with 1
623 ScaleIncX
= (1000 * width
) / width
;
624 ScaleIncY
= (1000 * height
) / height
;
627 out_row2
= out_row1
+ incX
;
628 /* we skipped 1280 bytes, it's almost two lines */
630 for (i
= 0; i
< y_div_2
-1; i
++) {
632 for (j
= 0; j
< x_div_2
; j
++) {
633 pointerIncX
+= ScaleIncX
;
635 u
= (unsigned char)(*bufUVYY
);
638 v
= (unsigned char)(*bufUVYY
);
641 y11
= (unsigned char)(*bufUVYY
);
644 y12
= (unsigned char)(*bufUVYY
);
647 y21
= (unsigned char)(*bufY
);
650 y22
= (unsigned char)(*bufY
);
653 if ((pointerIncX
> 999) && (pointerIncY
> 499)) {
660 *out_row1
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
662 *out_row1
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
664 *out_row1
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
673 *out_row1
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
675 *out_row1
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
677 *out_row1
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
681 // Second row of stream is displayed only
682 // if image is greath than half
684 if (ScaleIncY
> 501) {
691 *out_row2
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
693 *out_row2
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
695 *out_row2
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
704 *out_row2
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
706 *out_row2
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
708 *out_row2
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
714 // this comparation can be optimized and moved in
715 // if((pointerIncX>999)&&(pointerIncY>499))
717 if (pointerIncY
> 499)
719 /* Use 2 rows only if vertical ratio > 0.5 (increment is ratio*1000) */
720 if (ScaleIncY
> 501) {
721 out_row1
= out_row1
+ incX
;
722 out_row2
= out_row2
+ incX
;
725 pointerIncY
+= ScaleIncY
;
726 bufUVYY
= bufUVYY
+ width
;
727 bufY
= bufY
+ 2 * width
;