2 * @file microdia-decoder.c
3 * @author Nicolas VIVIEN
7 * @brief Driver for Microdia USB video camera
9 * @note Copyright (C) Nicolas VIVIEN
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <linux/module.h>
29 #include <linux/init.h>
30 #include <linux/kernel.h>
31 #include <linux/version.h>
32 #include <linux/errno.h>
33 #include <linux/slab.h>
34 #include <linux/kref.h>
36 #include <linux/usb.h>
37 #include <media/v4l2-common.h>
42 #define MAX(a, b) ((a) > (b) ? (a) : (b))
43 #define MIN(a, b) ((a) < (b) ? (a) : (b))
44 #define CLIP(a, low, high) MAX((low), MIN((high), (a)))
46 void raw6270_2i420(uint8_t *, uint8_t *, int,
47 int, const int, const int);
49 void raw6270_2RGB24(uint8_t *raw
, uint8_t *rgb
, int width
,
50 int height
, const int hflip
,
53 void raw6270_2BGR24(uint8_t *raw
, uint8_t *rgb
, int width
,
54 int height
, const int hflip
,
57 void microdia_getraw(uint8_t *, uint8_t *, int);
59 void microdia_raw2i420(uint8_t *, uint8_t *, int,
60 int, const int, const int);
62 void microdia_raw2bgr24(uint8_t *, uint8_t *, int,
63 int, const int, const int);
65 * @brief Decompress a frame
67 * This function permits to decompress a frame from the video stream.
69 * @param dev Device structure
70 * @param buffer Image data
72 * @returns 0 if all is OK
74 int microdia_decompress(struct usb_microdia
*dev
, struct v4l2_buffer
*buffer
)
91 dev
->flip_detect(dev
);
93 if (dev
->set_hvflip
) {
97 hflip
= dev
->vsettings
.hflip
;
98 vflip
= dev
->vsettings
.vflip
;
101 image
= dev
->queue
.scratch
;
103 data
= dev
->queue
.mem
+ buffer
->m
.offset
;
104 memcpy(image
, data
, MICRODIA_FRAME_SIZE
);
108 width
= dev
->vsettings
.format
.width
;
109 height
= dev
->vsettings
.format
.height
;
111 switch (dev
->vsettings
.format
.pixelformat
) {
112 case V4L2_PIX_FMT_RGB24
:
113 if (dev
->webcam_model
==
114 CAMERA_MODEL(USB_0C45_VID
, USB_6270_PID
) ||
116 CAMERA_MODEL(USB_0C45_VID
, USB_627B_PID
) ||
118 CAMERA_MODEL(USB_0C45_VID
, USB_6288_PID
) ||
120 CAMERA_MODEL(USB_0C45_VID
, USB_62B3_PID
) ||
122 CAMERA_MODEL(USB_0C45_VID
, USB_62BB_PID
) ||
124 CAMERA_MODEL(USB_145F_VID
, USB_013D_PID
)) {
125 raw6270_2RGB24(image
, data
, width
,
126 height
, hflip
, vflip
);
129 case V4L2_PIX_FMT_BGR24
:
130 if (dev
->webcam_model
==
131 CAMERA_MODEL(USB_0C45_VID
, USB_6270_PID
) ||
133 CAMERA_MODEL(USB_0C45_VID
, USB_627B_PID
) ||
135 CAMERA_MODEL(USB_0C45_VID
, USB_6288_PID
) ||
137 CAMERA_MODEL(USB_0C45_VID
, USB_62B3_PID
) ||
139 CAMERA_MODEL(USB_0C45_VID
, USB_62BB_PID
) ||
141 CAMERA_MODEL(USB_145F_VID
, USB_013D_PID
)) {
142 raw6270_2BGR24(image
, data
, width
,
143 height
, hflip
, vflip
);
145 microdia_raw2bgr24(image
, data
, width
,
146 height
, hflip
, vflip
);
149 case V4L2_PIX_FMT_YUV420
:
150 if (dev
->webcam_model
==
151 CAMERA_MODEL(USB_0C45_VID
, USB_6270_PID
) ||
153 CAMERA_MODEL(USB_0C45_VID
, USB_627B_PID
) ||
155 CAMERA_MODEL(USB_0C45_VID
, USB_6288_PID
) ||
157 CAMERA_MODEL(USB_0C45_VID
, USB_62B3_PID
) ||
159 CAMERA_MODEL(USB_0C45_VID
, USB_62BB_PID
) ||
161 CAMERA_MODEL(USB_145F_VID
, USB_013D_PID
)) {
162 raw6270_2i420(image
, data
, width
,
163 height
, hflip
, vflip
);
165 microdia_raw2i420(image
, data
, width
,
166 height
, hflip
, vflip
);
169 case V4L2_PIX_FMT_YUYV
:
174 buffer
->bytesused
= dev
->vsettings
.format
.sizeimage
;
180 * @brief This function permits to get the raw data. (without treatments)
182 * @param bayer Buffer with the bayer data
183 * @param size Length of bayer buffer
185 * @retval raw Buffer with the data from video sensor
187 void microdia_getraw(uint8_t *bayer
, uint8_t *raw
,
189 memcpy(raw
, bayer
, size
);
192 /* Table to translate Y offset to UV offset */
193 static int UVTranslate
[32] = {
204 static int Y_coords_624x
[128][2] = {
205 { 0, 0}, { 1, 0}, { 2, 0}, { 3, 0}, { 4, 0}, { 5, 0}, { 6, 0}, { 7, 0},
206 { 0, 1}, { 1, 1}, { 2, 1}, { 3, 1}, { 4, 1}, { 5, 1}, { 6, 1}, { 7, 1},
207 { 0, 2}, { 1, 2}, { 2, 2}, { 3, 2}, { 4, 2}, { 5, 2}, { 6, 2}, { 7, 2},
208 { 0, 3}, { 1, 3}, { 2, 3}, { 3, 3}, { 4, 3}, { 5, 3}, { 6, 3}, { 7, 3},
210 { 0, 4}, { 1, 4}, { 2, 4}, { 3, 4}, { 4, 4}, { 5, 4}, { 6, 4}, { 7, 4},
211 { 0, 5}, { 1, 5}, { 2, 5}, { 3, 5}, { 4, 5}, { 5, 5}, { 6, 5}, { 7, 5},
212 { 0, 6}, { 1, 6}, { 2, 6}, { 3, 6}, { 4, 6}, { 5, 6}, { 6, 6}, { 7, 6},
213 { 0, 7}, { 1, 7}, { 2, 7}, { 3, 7}, { 4, 7}, { 5, 7}, { 6, 7}, { 7, 7},
215 { 8, 0}, { 9, 0}, {10, 0}, {11, 0}, {12, 0}, {13, 0}, {14, 0}, {15, 0},
216 { 8, 1}, { 9, 1}, {10, 1}, {11, 1}, {12, 1}, {13, 1}, {14, 1}, {15, 1},
217 { 8, 2}, { 9, 2}, {10, 2}, {11, 2}, {12, 2}, {13, 2}, {14, 2}, {15, 2},
218 { 8, 3}, { 9, 3}, {10, 3}, {11, 3}, {12, 3}, {13, 3}, {14, 3}, {15, 3},
220 { 8, 4}, { 9, 4}, {10, 4}, {11, 4}, {12, 4}, {13, 4}, {14, 4}, {15, 4},
221 { 8, 5}, { 9, 5}, {10, 5}, {11, 5}, {12, 5}, {13, 5}, {14, 5}, {15, 5},
222 { 8, 6}, { 9, 6}, {10, 6}, {11, 6}, {12, 6}, {13, 6}, {14, 6}, {15, 6},
223 { 8, 7}, { 9, 7}, {10, 7}, {11, 7}, {12, 7}, {13, 7}, {14, 7}, {15, 7}
226 void microdia_raw2bgr24(uint8_t *raw
, uint8_t *rgb
,
227 int width
, int height
, const int hflip
,
230 int i
= 0, x
= 0, y
= 0;
231 unsigned char *buf
= raw
;
232 unsigned char *buf3
= rgb
;
234 while (i
< (width
* height
+ (width
* height
) / 2)) {
236 for (tile
= 0; tile
< 4; tile
++) {
239 for (subY
= 0; subY
< 4; subY
++) {
240 for (subX
= 0; subX
< 8; subX
++) {
241 int subI
= i
+ tile
* 32 + 8 * subY
+ subX
;
242 int subU
= i
+ 128 + UVTranslate
[tile
* 8 + 4 * (subY
>> 1) + (subX
>> 1)];
243 int subV
= subU
+ 32;
245 int relX
= x
+ (((tile
== 0) || (tile
== 1)) ? 0 : 8) + subX
; /* tile 0, 1 to into left column*/
246 int relY
= y
+ (((tile
== 0) || (tile
== 2)) ? 0 : 4) + subY
; /* tile 0, 2 go into top row */
251 relY
= height
- relY
;
253 if ((relX
< width
) && (relY
< height
)) {
260 ptr
= buf3
+ relY
* width
* 3 + relX
* 3;
261 *ptr
= CLIP((298 * c
+ 516 * d
+ 128) >> 8, 0, 255);
263 *ptr
= CLIP((298 * c
- 100 * d
- 208 * e
+ 128) >> 8, 0, 255);
265 *ptr
= CLIP((298 * c
+ 409 * e
+ 128) >> 8, 0, 255);
280 void microdia_raw2i420(uint8_t *raw
, uint8_t *i420
,
281 int width
, int height
, const int hflip
,
284 int i
= 0, x
= 0, y
= 0, j
, relX
, relY
, x_div2
, y_div2
;
285 unsigned char *buf
= raw
, *ptr
;
286 unsigned char *buf3
= i420
;
287 int view_size
= width
* height
;
288 int view_size_div4
= view_size
>> 2;
289 int image_x_div2
= width
>> 1;
290 int image_y_div2
= height
>> 1;
291 int view_x_div2
= width
>> 1;
293 while (i
< (width
* height
+ (width
* height
) / 2)) {
294 for (j
= 0; j
< 128; j
++) {
295 relX
= x
+ Y_coords_624x
[j
][0];
296 relY
= y
+ Y_coords_624x
[j
][1];
298 relX
= width
- relX
- 1;
300 relY
= height
- relY
- 1;
302 if ((relX
< width
) && (relY
< height
)) {
303 ptr
= buf3
+ relY
* width
+ relX
;
310 for (j
= 0; j
< 32; j
++) {
311 relX
= (x_div2
) + (j
& 0x07);
312 relY
= (y_div2
) + (j
>> 3);
314 relX
= image_x_div2
- relX
- 1;
316 relY
= image_y_div2
- relY
- 1;
318 if ((relX
< width
) && (relY
< height
)) {
319 ptr
= buf3
+ view_size
+
320 relY
* (view_x_div2
) + relX
;
321 *ptr
= buf
[i
+ 128 + j
];
322 ptr
+= view_size_div4
;
323 *ptr
= buf
[i
+ 160 + j
];
339 * @brief This function permits to convert an image from 6270 raw format to i420
340 * @param raw Buffer with the bayer data
341 * @param image Size of image
342 * @param view Size of view
343 * @param hflip Horizontal flip - not implemented
344 * @param vflip Vertical flip - not implemented
346 * @retval i420 Buffer with the i420 data
347 * Format of stream is uvyy,uvyy - repeated 320 times for 640x480
348 y - repeated 640 times for 640x480
349 First 1280 bytes is maybe dummy ***FIXME***
352 void raw6270_2i420(uint8_t *raw
, uint8_t *i420
, int width
,
353 int height
, const int hflip
,
356 int i
, j
, YIndex
= 0, UVIndex
= 0;
357 unsigned char *y
, *u
, *v
;
359 /* For fast calculations */
360 int x_div_2
, y_div_2
;
361 /* Skip first 1280 bytes strange dummy bytes */
364 x_div_2
= width
/ 2; /* for fast calculation if x=640 x_div_2=320 */
365 y_div_2
= height
/ 2; /* for fast calculation if y=480 y_div_4=240 */
368 u
= i420
+ width
* height
;
369 v
= i420
+ width
* height
+ (width
>> 1) * (height
>> 1);
373 /* we skipped 1280 bytes, it's almost two lines */
374 for (i
= 0; i
< y_div_2
- 1; i
++) {
375 for (j
= 0; j
< x_div_2
; j
++) {
391 for (j
= 0; j
< width
; j
++) {
400 UVIndex
+= (width
>> 1);
406 * @brief This function permits to convert an image from 6270 rawformat to BGR24
407 * @param raw Buffer with the bayer data
408 * @param image Size of image
409 * @param view Size of view
410 * @param hflip Horizontal flip - not implemented yet
411 * @param vflip Vertical flip - not implemented yet
413 * @retval rgb Buffer with the rgb data
414 Format of stream is uvyy,uvyy - repeated 320 times for 640x480
415 y - repeated 640 times for 640x480
416 First 1280 bytes is maybe dumy ***FIXME***
419 void raw6270_2BGR24(uint8_t *raw
, uint8_t *rgb
, int width
,
420 int height
, const int hflip
,
424 /* Maybe is not necesery to use long variables but I not sure in this moment */
425 long y11
, y12
, y21
, y22
, u
, v
, y
, C
, D
, E
;
426 long ScaleIncX
, ScaleIncY
;
427 long pointerIncX
, pointerIncY
;
433 /* For fast calculations*/
434 int x_div_2
, y_div_2
;
435 /* Skip first 1280 bytes strange dummy bytes */
438 x_div_2
= width
/ 2; /* for fast calculation if x=640 x_div_2=320 */
439 y_div_2
= height
/ 2; /* for fast calculation if y=480 y_div_4=240 */
440 incX
= 3 * width
; /* Incrementation koeficient for next row*/
442 bufY
= raw
+ 2 * width
;
445 // Because I can't use float ratio is multiply by 1000
446 // then 1000 is equal of increment image (X or Y) with 1
448 ScaleIncX
= (1000 * width
) / width
;
449 ScaleIncY
= (1000 * height
) / height
;
452 out_row2
= out_row1
+ incX
;
453 /* we skipped 1280 bytes, it's almost two lines*/
455 for (i
= 0; i
< y_div_2
-1; i
++) {
457 for (j
= 0; j
< x_div_2
; j
++) {
458 pointerIncX
+= ScaleIncX
;
460 u
= (unsigned char)(*bufUVYY
);
463 v
= (unsigned char)(*bufUVYY
);
466 y11
= (unsigned char)(*bufUVYY
);
469 y12
= (unsigned char)(*bufUVYY
);
472 y21
= (unsigned char)(*bufY
);
475 y22
= (unsigned char)(*bufY
);
478 if ((pointerIncX
> 999) && (pointerIncY
> 499)) {
485 *out_row1
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
487 *out_row1
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
489 *out_row1
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
499 *out_row1
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
501 *out_row1
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
503 *out_row1
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
507 // Second row of stream is displayed only
508 // if image is greath than half
510 if (ScaleIncY
> 501) {
517 *out_row2
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
519 *out_row2
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
521 *out_row2
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
530 *out_row2
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
532 *out_row2
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
534 *out_row2
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
540 // this comparation can be optimized and moved in
541 // if((pointerIncX>999)&&(pointerIncY>499))
543 if (pointerIncY
> 499)
546 // Use 2 rows only if
547 // vertical ratio > 0.5 (increment is ratio*1000)
549 if (ScaleIncY
> 501) {
550 out_row1
= out_row1
+ incX
;
551 out_row2
= out_row2
+ incX
;
554 pointerIncY
+= ScaleIncY
;
555 bufUVYY
= bufUVYY
+ width
;
556 bufY
= bufY
+ 2 * width
;
562 * @brief This function permits to convert an image from 6270 rawformat to RGB24
563 * @brief The same function as convert to BGR24 but only B and R is change order
564 * @param raw Buffer with the bayer data
565 * @param image Size of image
566 * @param view Size of view
567 * @param hflip Horizontal flip
568 * @param vflip Vertical flip
570 * @retval rgb Buffer with the rgb data
571 Format of stream is uvyy,uvyy - repeated 320 times for 640x480
572 y - repeated 640 times for 640x480
573 First 1280 bytes is maybe dumy ***FIXME***
576 void raw6270_2RGB24(uint8_t *raw
, uint8_t *rgb
, int width
,
577 int height
, const int hflip
,
581 /* Maybe is not necesery to use long variables but I not sure in this moment */
582 long y11
, y12
, y21
, y22
, u
, v
, y
, C
, D
, E
;
583 long ScaleIncX
, ScaleIncY
;
584 long pointerIncX
, pointerIncY
;
590 /* For fast calculations */
591 int x_div_2
, y_div_2
;
592 /* Skip first 1280 bytes strange dummy bytes */
595 x_div_2
= width
/ 2; /* for fast calculation if x=640 x_div_2=320 */
596 y_div_2
= height
/ 2; /* for fast calculation if y=480 y_div_4=240 */
599 bufY
= raw
+ 2 * width
;
602 // Because I can't use float ratio is multiply by 1000 then
603 // 1000 is equal of increment image (X or Y) with 1
605 ScaleIncX
= (1000 * width
) / width
;
606 ScaleIncY
= (1000 * height
) / height
;
609 out_row2
= out_row1
+ incX
;
610 /* we skipped 1280 bytes, it's almost two lines */
612 for (i
= 0; i
< y_div_2
-1; i
++) {
614 for (j
= 0; j
< x_div_2
; j
++) {
615 pointerIncX
+= ScaleIncX
;
617 u
= (unsigned char)(*bufUVYY
);
620 v
= (unsigned char)(*bufUVYY
);
623 y11
= (unsigned char)(*bufUVYY
);
626 y12
= (unsigned char)(*bufUVYY
);
629 y21
= (unsigned char)(*bufY
);
632 y22
= (unsigned char)(*bufY
);
635 if ((pointerIncX
> 999) && (pointerIncY
> 499)) {
642 *out_row1
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
644 *out_row1
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
646 *out_row1
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
655 *out_row1
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
657 *out_row1
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
659 *out_row1
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
663 // Second row of stream is displayed only
664 // if image is greath than half
666 if (ScaleIncY
> 501) {
673 *out_row2
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
675 *out_row2
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
677 *out_row2
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
686 *out_row2
= CLIP((298 * C
+ 409 * E
+ 128) >> 8, 0, 255);
688 *out_row2
= CLIP((298 * C
- 100 * D
- 208 * E
+ 128) >> 8, 0, 255);
690 *out_row2
= CLIP((298 * C
+ 516 * D
+ 128) >> 8, 0, 255);
696 // this comparation can be optimized and moved in
697 // if((pointerIncX>999)&&(pointerIncY>499))
699 if (pointerIncY
> 499)
701 /* Use 2 rows only if vertical ratio > 0.5 (increment is ratio*1000) */
702 if (ScaleIncY
> 501) {
703 out_row1
= out_row1
+ incX
;
704 out_row2
= out_row2
+ incX
;
707 pointerIncY
+= ScaleIncY
;
708 bufUVYY
= bufUVYY
+ width
;
709 bufY
= bufY
+ 2 * width
;