1 /*
2 pygame - Python Game Library
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library 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 GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with this library; if not, write to the Free
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18 */
19
20 /*
21 * Camera - webcam support for pygame
22 * Author: Nirav Patel
23 *
24 * This module allows for use of v4l2 webcams in pygame. The code is written
25 * such that adding support for vfw cameras should be possible without
26 * much modification of existing functions. v4l2 functions are kept seperate
27 * from functions available to pygame users and generic functions like
28 * colorspace conversion.
29 *
30 * There is currently support for cameras that support MMAP and use
31 * pixelformats of RGB24, RGB444, YUYV, SBGGR8, and YUV420. To add support for
32 * additional pixelformats, add them to v4l2_init_device and
33 * v4l2_process_image, and add functions to convert the format to packed RGB,
34 * YUV, and HSV.
35 */
36
37 #include "camera.h"
38 #include "pgcompat.h"
39
40 /*
41 #if defined(__unix__) || !defined(__APPLE__)
42 #else
43 #define V4L2_PIX_FMT_RGB24 1
44 #define V4L2_PIX_FMT_RGB444 1
45 #endif
46 */
47
48 /* functions available to pygame users */
49 PyObject *
50 surf_colorspace(PyObject *self, PyObject *arg);
51 PyObject *
52 list_cameras(PyObject *self, PyObject *arg);
53 PyObject *
54 camera_start(pgCameraObject *self, PyObject *args);
55 PyObject *
56 camera_stop(pgCameraObject *self, PyObject *args);
57 PyObject *
58 camera_get_controls(pgCameraObject *self, PyObject *args);
59 PyObject *
60 camera_set_controls(pgCameraObject *self, PyObject *arg, PyObject *kwds);
61 PyObject *
62 camera_get_size(pgCameraObject *self, PyObject *args);
63 PyObject *
64 camera_query_image(pgCameraObject *self, PyObject *args);
65 PyObject *
66 camera_get_image(pgCameraObject *self, PyObject *arg);
67 PyObject *
68 camera_get_raw(pgCameraObject *self, PyObject *args);
69
70 /*
71 * Functions available to pygame users. The idea is to make these as simple as
72 * possible, and merely have them call functions specific to the type of
73 * camera being used to do all the real work. It currently just calls v4l2_*
74 * functions, but it could check something like self->cameratype and depending
75 * on the result, call v4l, v4l2, vfw, or other functions.
76 */
77
78 /* colorspace() - Surface colorspace conversion */
79 PyObject *
surf_colorspace(PyObject * self,PyObject * arg)80 surf_colorspace(PyObject *self, PyObject *arg)
81 {
82 pgSurfaceObject *surfobj, *surfobj2;
83 SDL_Surface *surf, *newsurf;
84 char *color;
85 int cspace;
86 surfobj2 = NULL;
87
88 /*get all the arguments*/
89 if (!PyArg_ParseTuple(arg, "O!s|O!", &pgSurface_Type, &surfobj, &color,
90 &pgSurface_Type, &surfobj2))
91 return NULL;
92
93 if (!strcmp(color, "YUV")) {
94 cspace = YUV_OUT;
95 }
96 else if (!strcmp(color, "HSV")) {
97 cspace = HSV_OUT;
98 }
99 else {
100 return RAISE(PyExc_ValueError, "Incorrect colorspace value");
101 }
102
103 surf = pgSurface_AsSurface(surfobj);
104
105 if (!surfobj2) {
106 newsurf = SDL_CreateRGBSurface(
107 0, surf->w, surf->h, surf->format->BitsPerPixel,
108 surf->format->Rmask, surf->format->Gmask, surf->format->Bmask,
109 surf->format->Amask);
110 if (!newsurf) {
111 return NULL;
112 }
113 }
114 else {
115 newsurf = pgSurface_AsSurface(surfobj2);
116 }
117
118 /* check to see if the size is the same. */
119 if (newsurf->w != surf->w || newsurf->h != surf->h)
120 return RAISE(PyExc_ValueError,
121 "Surfaces not the same width and height.");
122
123 /* check to see if the format of the surface is the same. */
124 if (surf->format->BitsPerPixel != newsurf->format->BitsPerPixel)
125 return RAISE(PyExc_ValueError, "Surfaces not the same depth");
126
127 SDL_LockSurface(newsurf);
128 pgSurface_Lock(surfobj);
129
130 Py_BEGIN_ALLOW_THREADS;
131 colorspace(surf, newsurf, cspace);
132 Py_END_ALLOW_THREADS;
133
134 pgSurface_Unlock(surfobj);
135 SDL_UnlockSurface(newsurf);
136
137 if (surfobj2) {
138 Py_INCREF(surfobj2);
139 return (PyObject *)surfobj2;
140 }
141 else
142 return (PyObject *)pgSurface_New(newsurf);
143 }
144
145 /* list_cameras() - lists cameras available on the computer */
146 PyObject *
list_cameras(PyObject * self,PyObject * arg)147 list_cameras(PyObject *self, PyObject *arg)
148 {
149 #if defined(__unix__) || defined(PYGAME_WINDOWS_CAMERA)
150 PyObject *ret_list;
151 PyObject *string;
152 #if !defined(PYGAME_WINDOWS_CAMERA)
153 char **devices;
154 #else
155 WCHAR **devices;
156 #endif
157 int num_devices, i;
158
159 num_devices = 0;
160 ret_list = NULL;
161 ret_list = PyList_New(0);
162 if (!ret_list)
163 return NULL;
164
165 #if defined(__unix__)
166 devices = v4l2_list_cameras(&num_devices);
167 #elif defined(PYGAME_WINDOWS_CAMERA)
168 devices = windows_list_cameras(&num_devices);
169 #endif
170 for (i = 0; i < num_devices; i++) {
171 #if defined(PYGAME_WINDOWS_CAMERA)
172 string = PyUnicode_FromWideChar(devices[i], -1);
173 #else
174 string = Text_FromUTF8(devices[i]);
175 #endif
176 if (0 != PyList_Append(ret_list, string)) {
177 /* Append failed; clean up and return */
178 Py_DECREF(ret_list);
179 Py_DECREF(string);
180 for (; i < num_devices; i++) {
181 free(devices[i]);
182 }
183 free(devices);
184 return NULL; /* Exception already set. */
185 }
186 Py_DECREF(string);
187 free(devices[i]);
188 }
189 free(devices);
190
191 return ret_list;
192 #else
193 Py_RETURN_NONE;
194 #endif
195 }
196
197 /* start() - opens, inits, and starts capturing on the camera */
198 PyObject *
camera_start(pgCameraObject * self,PyObject * args)199 camera_start(pgCameraObject *self, PyObject *args)
200 {
201 #if defined(__unix__)
202 if (v4l2_open_device(self) == 0) {
203 v4l2_close_device(self);
204 return NULL;
205 }
206 else {
207 self->camera_type = CAM_V4L2;
208 if (v4l2_init_device(self) == 0) {
209 v4l2_close_device(self);
210 return NULL;
211 }
212 if (v4l2_start_capturing(self) == 0) {
213 v4l2_close_device(self);
214 return NULL;
215 }
216 }
217 #elif defined(PYGAME_WINDOWS_CAMERA)
218 if (self->open) { /* camera already started */
219 Py_RETURN_NONE;
220 }
221
222 if (!windows_open_device(self)) {
223 windows_close_device(self);
224 return NULL;
225 }
226 #endif
227 Py_RETURN_NONE;
228 }
229
230 /* stop() - stops capturing, uninits, and closes the camera */
231 PyObject *
camera_stop(pgCameraObject * self,PyObject * args)232 camera_stop(pgCameraObject *self, PyObject *args)
233 {
234 #if defined(__unix__)
235 if (v4l2_stop_capturing(self) == 0)
236 return NULL;
237 if (v4l2_uninit_device(self) == 0)
238 return NULL;
239 if (v4l2_close_device(self) == 0)
240 return NULL;
241 #elif defined(PYGAME_WINDOWS_CAMERA)
242 if (self->open) { /* camera started */
243 if (!windows_close_device(self))
244 return NULL;
245 }
246 #endif
247 Py_RETURN_NONE;
248 }
249
250 /* get_controls() - gets current values of user controls */
251 /* TODO: Support brightness, contrast, and other common controls */
252 PyObject *
camera_get_controls(pgCameraObject * self,PyObject * args)253 camera_get_controls(pgCameraObject *self, PyObject *args)
254 {
255 #if defined(__unix__)
256 int value;
257 if (v4l2_get_control(self->fd, V4L2_CID_HFLIP, &value))
258 self->hflip = value;
259
260 if (v4l2_get_control(self->fd, V4L2_CID_VFLIP, &value))
261 self->vflip = value;
262
263 if (v4l2_get_control(self->fd, V4L2_CID_BRIGHTNESS, &value))
264 self->brightness = value;
265
266 return Py_BuildValue("(NNN)", PyBool_FromLong(self->hflip),
267 PyBool_FromLong(self->vflip),
268 PyInt_FromLong(self->brightness));
269 #elif defined(PYGAME_WINDOWS_CAMERA)
270 return Py_BuildValue("(NNN)", PyBool_FromLong(self->hflip),
271 PyBool_FromLong(self->vflip), PyInt_FromLong(-1));
272 #endif
273 Py_RETURN_NONE;
274 }
275
276 /* set_controls() - changes camera settings if supported by the camera */
277 PyObject *
camera_set_controls(pgCameraObject * self,PyObject * arg,PyObject * kwds)278 camera_set_controls(pgCameraObject *self, PyObject *arg, PyObject *kwds)
279 {
280 #if defined(__unix__)
281 int hflip = 0, vflip = 0, brightness = 0;
282 char *kwids[] = {"hflip", "vflip", "brightness", NULL};
283
284 camera_get_controls(self, NULL);
285 hflip = self->hflip;
286 vflip = self->vflip;
287 brightness = self->brightness;
288
289 if (!PyArg_ParseTupleAndKeywords(arg, kwds, "|iii", kwids, &hflip, &vflip,
290 &brightness))
291 return NULL;
292
293 /* #if defined(__unix__) */
294 if (v4l2_set_control(self->fd, V4L2_CID_HFLIP, hflip))
295 self->hflip = hflip;
296
297 if (v4l2_set_control(self->fd, V4L2_CID_VFLIP, vflip))
298 self->vflip = vflip;
299
300 if (v4l2_set_control(self->fd, V4L2_CID_BRIGHTNESS, brightness))
301 self->brightness = brightness;
302
303 return Py_BuildValue("(NNN)", PyBool_FromLong(self->hflip),
304 PyBool_FromLong(self->vflip),
305 PyInt_FromLong(self->brightness));
306
307 #elif defined(PYGAME_WINDOWS_CAMERA)
308 int hflip = 0, vflip = 0, brightness = 0;
309 char *kwids[] = {"hflip", "vflip", "brightness", NULL};
310
311 hflip = self->hflip;
312 vflip = self->vflip;
313 brightness = -1;
314
315 if (!PyArg_ParseTupleAndKeywords(arg, kwds, "|iii", kwids, &hflip, &vflip,
316 &brightness))
317 return NULL;
318
319 self->hflip = hflip;
320 self->vflip = vflip;
321
322 return Py_BuildValue("(NNN)", PyBool_FromLong(self->hflip),
323 PyBool_FromLong(self->vflip), PyInt_FromLong(-1));
324 #endif
325 Py_RETURN_NONE;
326 }
327
328 /* get_size() - returns the dimensions of the images being recorded */
329 PyObject *
camera_get_size(pgCameraObject * self,PyObject * args)330 camera_get_size(pgCameraObject *self, PyObject *args)
331 {
332 #if defined(__unix__) || defined(PYGAME_WINDOWS_CAMERA)
333 return Py_BuildValue("(ii)", self->width, self->height);
334 #endif
335 Py_RETURN_NONE;
336 }
337
338 /* query_image() - checks if a frame is ready */
339 PyObject *
camera_query_image(pgCameraObject * self,PyObject * args)340 camera_query_image(pgCameraObject *self, PyObject *args)
341 {
342 #if defined(__unix__)
343 return PyBool_FromLong(v4l2_query_buffer(self));
344 #elif defined(PYGAME_WINDOWS_CAMERA)
345 int ready;
346 if (!windows_frame_ready(self, &ready))
347 return NULL;
348
349 return PyBool_FromLong(ready);
350 #endif
351 Py_RETURN_TRUE;
352 }
353
354 /* get_image() - returns an RGB Surface */
355 /* code to reuse Surface from René Dudfield */
356 PyObject *
camera_get_image(pgCameraObject * self,PyObject * arg)357 camera_get_image(pgCameraObject *self, PyObject *arg)
358 {
359 #if defined(__unix__)
360 SDL_Surface *surf = NULL;
361 pgSurfaceObject *surfobj = NULL;
362
363 if (!PyArg_ParseTuple(arg, "|O!", &pgSurface_Type, &surfobj))
364 return NULL;
365
366 if (!surfobj) {
367 surf = SDL_CreateRGBSurface(0, self->width, self->height, 24,
368 0xFF << 16, 0xFF << 8, 0xFF, 0);
369 }
370 else {
371 surf = pgSurface_AsSurface(surfobj);
372 }
373
374 if (!surf)
375 return NULL;
376
377 if (surf->w != self->width || surf->h != self->height) {
378 return RAISE(PyExc_ValueError,
379 "Destination surface not the correct width or height.");
380 }
381
382 Py_BEGIN_ALLOW_THREADS;
383 if (!v4l2_read_frame(self, surf))
384 return NULL;
385 Py_END_ALLOW_THREADS;
386
387 if (!surf)
388 return NULL;
389
390 if (surfobj) {
391 Py_INCREF(surfobj);
392 return (PyObject *)surfobj;
393 }
394 else {
395 return (PyObject *)pgSurface_New(surf);
396 }
397 #elif defined(PYGAME_WINDOWS_CAMERA)
398 SDL_Surface *surf = NULL;
399 pgSurfaceObject *surfobj = NULL;
400
401 int width = self->width;
402 int height = self->height;
403
404 if (!PyArg_ParseTuple(arg, "|O!", &pgSurface_Type, &surfobj))
405 return NULL;
406
407 if (!surfobj) {
408 surf = SDL_CreateRGBSurface(0, width, height, 32, // 24?
409 0xFF << 16, 0xFF << 8, 0xFF, 0);
410 }
411 else {
412 surf = pgSurface_AsSurface(surfobj);
413 }
414
415 if (!surf)
416 return NULL;
417
418 if (surf->w != self->width || surf->h != self->height) {
419 return RAISE(PyExc_ValueError,
420 "Destination surface not the correct width or height.");
421 }
422
423 if (!windows_read_frame(self, surf))
424 return NULL;
425
426 if (!surf)
427 return NULL;
428
429 if (surfobj) {
430 Py_INCREF(surfobj);
431 return (PyObject *)surfobj;
432 }
433 else {
434 return (PyObject *)pgSurface_New(surf);
435 }
436
437 #endif
438 Py_RETURN_NONE;
439 }
440
441 /* get_raw() - returns an unmodified image as a string from the buffer */
442 PyObject *
camera_get_raw(pgCameraObject * self,PyObject * args)443 camera_get_raw(pgCameraObject *self, PyObject *args)
444 {
445 #if defined(__unix__)
446 return v4l2_read_raw(self);
447 #elif defined(PYGAME_WINDOWS_CAMERA)
448 return windows_read_raw(self);
449 #endif
450 Py_RETURN_NONE;
451 }
452
453 /*
454 * Pixelformat conversion functions
455 */
456
457 /* converts from rgb Surface to yuv or hsv */
458 /* TODO: Allow for conversion from yuv and hsv to all */
459 void
colorspace(SDL_Surface * src,SDL_Surface * dst,int cspace)460 colorspace(SDL_Surface *src, SDL_Surface *dst, int cspace)
461 {
462 switch (cspace) {
463 case YUV_OUT:
464 rgb_to_yuv(src->pixels, dst->pixels, src->h * src->w, 0,
465 src->format);
466 break;
467 case HSV_OUT:
468 rgb_to_hsv(src->pixels, dst->pixels, src->h * src->w, 0,
469 src->format);
470 break;
471 }
472 }
473
474 /* converts pretty directly if its already RGB24 */
475 void
rgb24_to_rgb(const void * src,void * dst,int length,SDL_PixelFormat * format)476 rgb24_to_rgb(const void *src, void *dst, int length, SDL_PixelFormat *format)
477 {
478 Uint8 *s = (Uint8 *)src;
479 Uint8 *d8;
480 Uint16 *d16;
481 Uint32 *d32;
482 Uint8 r, g, b;
483 int rshift, gshift, bshift, rloss, gloss, bloss;
484
485 rshift = format->Rshift;
486 gshift = format->Gshift;
487 bshift = format->Bshift;
488 rloss = format->Rloss;
489 gloss = format->Gloss;
490 bloss = format->Bloss;
491
492 switch (format->BytesPerPixel) {
493 case 1:
494 d8 = (Uint8 *)dst;
495 while (length--) {
496 r = *s++;
497 g = *s++;
498 b = *s++;
499 *d8++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
500 ((b >> bloss) << bshift);
501 }
502 break;
503 case 2:
504 d16 = (Uint16 *)dst;
505 while (length--) {
506 r = *s++;
507 g = *s++;
508 b = *s++;
509 *d16++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
510 ((b >> bloss) << bshift);
511 }
512 break;
513 case 3:
514 d8 = (Uint8 *)dst;
515 while (length--) {
516 *d8++ = *(s + 2); /* blue */
517 *d8++ = *(s + 1); /* green */
518 *d8++ = *s; /* red */
519 s += 3;
520 }
521 break;
522 default:
523 d32 = (Uint32 *)dst;
524 while (length--) {
525 r = *s++;
526 g = *s++;
527 b = *s++;
528 *d32++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
529 ((b >> bloss) << bshift);
530 }
531 break;
532 }
533 }
534
535 /* slight variation on rgb24_to_rgb, just drops the 4th byte of each pixel,
536 * changes the R, G, B ordering. */
537 void
bgr32_to_rgb(const void * src,void * dst,int length,SDL_PixelFormat * format)538 bgr32_to_rgb(const void *src, void *dst, int length, SDL_PixelFormat *format)
539 {
540 Uint8 *s = (Uint8 *)src;
541 Uint8 *d8;
542 Uint16 *d16;
543 Uint32 *d32;
544 Uint8 r, g, b;
545 int rshift, gshift, bshift, rloss, gloss, bloss;
546
547 rshift = format->Rshift;
548 gshift = format->Gshift;
549 bshift = format->Bshift;
550 rloss = format->Rloss;
551 gloss = format->Gloss;
552 bloss = format->Bloss;
553
554 switch (format->BytesPerPixel) {
555 case 1:
556 d8 = (Uint8 *)dst;
557 while (length--) {
558 b = *s++;
559 g = *s++;
560 r = *s++;
561 s++;
562 *d8++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
563 ((b >> bloss) << bshift);
564 }
565 break;
566 case 2:
567 d16 = (Uint16 *)dst;
568 while (length--) {
569 b = *s++;
570 g = *s++;
571 r = *s++;
572 s++;
573 *d16++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
574 ((b >> bloss) << bshift);
575 }
576 break;
577 case 3:
578 d8 = (Uint8 *)dst;
579 while (length--) {
580 *d8++ = *s; /* red */
581 *d8++ = *(s + 1); /* green */
582 *d8++ = *(s + 2); /* blue */
583 s += 4;
584 }
585 break;
586 default:
587 d32 = (Uint32 *)dst;
588 while (length--) {
589 b = *s++;
590 g = *s++;
591 r = *s++;
592 *s++;
593 *d32++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
594 ((b >> bloss) << bshift);
595 }
596 break;
597 }
598 }
599
600 /* converts packed rgb to packed hsv. formulas modified from wikipedia */
601 void
rgb_to_hsv(const void * src,void * dst,int length,unsigned long source,SDL_PixelFormat * format)602 rgb_to_hsv(const void *src, void *dst, int length, unsigned long source,
603 SDL_PixelFormat *format)
604 {
605 Uint8 *s8, *d8;
606 Uint16 *s16, *d16;
607 Uint32 *s32, *d32;
608 Uint8 r, g, b, p1, p2, h, s, v, max, min, delta;
609 int rshift, gshift, bshift, rloss, gloss, bloss;
610
611 s8 = (Uint8 *)src;
612 s16 = (Uint16 *)src;
613 s32 = (Uint32 *)src;
614 d8 = (Uint8 *)dst;
615 d16 = (Uint16 *)dst;
616 d32 = (Uint32 *)dst;
617 rshift = format->Rshift;
618 gshift = format->Gshift;
619 bshift = format->Bshift;
620 rloss = format->Rloss;
621 gloss = format->Gloss;
622 bloss = format->Bloss;
623
624 /* you could stick the if statement inside the loop, but I'm sacrificing a
625 a few hundred bytes for a little performance */
626 /* 10 yrs later... about that... */
627 if (source == V4L2_PIX_FMT_RGB444 || source == V4L2_PIX_FMT_RGB24 ||
628 source == V4L2_PIX_FMT_XBGR32) {
629 while (length--) {
630 if (source == V4L2_PIX_FMT_RGB444) {
631 p1 = *s8++;
632 p2 = *s8++;
633 b = p2 << 4;
634 g = p1 & 0xF0;
635 r = p1 << 4;
636 }
637 else if (source == V4L2_PIX_FMT_RGB24) {
638 r = *s8++;
639 g = *s8++;
640 b = *s8++;
641 }
642 else {
643 b = *s8++;
644 g = *s8++;
645 r = *s8++;
646 s8++;
647 }
648 max = MAX(MAX(r, g), b);
649 min = MIN(MIN(r, g), b);
650 delta = max - min;
651 v = max; /* value (similar to luminosity) */
652 if (!delta) { /* grey, zero hue and saturation */
653 s = 0;
654 h = 0;
655 }
656 else {
657 s = 255 * delta / max; /* saturation */
658 if (r == max) { /* set hue based on max color */
659 h = 43 * (g - b) / delta;
660 }
661 else if (g == max) {
662 h = 85 + 43 * (b - r) / delta;
663 }
664 else {
665 h = 170 + 43 * (r - g) / delta;
666 }
667 }
668 switch (format->BytesPerPixel) {
669 case 1:
670 *d8++ = ((h >> rloss) << rshift) |
671 ((s >> gloss) << gshift) |
672 ((v >> bloss) << bshift);
673 break;
674 case 2:
675 *d16++ = ((h >> rloss) << rshift) |
676 ((s >> gloss) << gshift) |
677 ((v >> bloss) << bshift);
678 break;
679 case 3:
680 *d8++ = v;
681 *d8++ = s;
682 *d8++ = h;
683 break;
684 default:
685 *d32++ = ((h >> rloss) << rshift) |
686 ((s >> gloss) << gshift) |
687 ((v >> bloss) << bshift);
688 break;
689 }
690 }
691 }
692 else { /* for use as stage 2 in yuv or bayer to hsv, r and b switched */
693 while (length--) {
694 switch (format->BytesPerPixel) {
695 case 1:
696 r = *s8 >> rshift << rloss;
697 g = *s8 >> gshift << gloss;
698 b = *s8++ >> bshift << bloss;
699 break;
700 case 2:
701 r = *s16 >> rshift << rloss;
702 g = *s16 >> gshift << gloss;
703 b = *s16++ >> bshift << bloss;
704 break;
705 case 3:
706 b = *s8++;
707 g = *s8++;
708 r = *s8++;
709 break;
710 default:
711 r = *s32 >> rshift << rloss;
712 g = *s32 >> gshift << gloss;
713 b = *s32++ >> bshift << bloss;
714 break;
715 }
716 max = MAX(MAX(r, g), b);
717 min = MIN(MIN(r, g), b);
718 delta = max - min;
719 v = max; /* value (similar to luminosity) */
720 if (!delta) { /* grey, zero hue and saturation */
721 s = 0;
722 h = 0;
723 }
724 else {
725 s = 255 * delta / max; /* saturation */
726 if (r == max) { /* set hue based on max color */
727 h = 43 * (g - b) / delta;
728 }
729 else if (g == max) {
730 h = 85 + 43 * (b - r) / delta;
731 }
732 else {
733 h = 170 + 43 * (r - g) / delta;
734 }
735 }
736 switch (format->BytesPerPixel) {
737 case 1:
738 *d8++ = ((h >> rloss) << rshift) |
739 ((s >> gloss) << gshift) |
740 ((v >> bloss) << bshift);
741 break;
742 case 2:
743 *d16++ = ((h >> rloss) << rshift) +
744 ((s >> gloss) << gshift) +
745 ((v >> bloss) << bshift);
746 break;
747 case 3:
748 *d8++ = v;
749 *d8++ = s;
750 *d8++ = h;
751 break;
752 default:
753 *d32++ = ((h >> rloss) << rshift) |
754 ((s >> gloss) << gshift) |
755 ((v >> bloss) << bshift);
756 break;
757 }
758 }
759 }
760 }
761
762 /* convert packed rgb to yuv. Note that unlike many implementations of YUV,
763 this has a full range of 0-255 for Y, not 16-235. Formulas from wikipedia */
764 void
rgb_to_yuv(const void * src,void * dst,int length,unsigned long source,SDL_PixelFormat * format)765 rgb_to_yuv(const void *src, void *dst, int length, unsigned long source,
766 SDL_PixelFormat *format)
767 {
768 Uint8 *s8, *d8;
769 Uint16 *s16, *d16;
770 Uint32 *s32, *d32;
771 Uint8 r, g, b, y, u, v;
772 Uint8 p1, p2;
773 int rshift, gshift, bshift, rloss, gloss, bloss;
774
775 s8 = (Uint8 *)src;
776 s16 = (Uint16 *)src;
777 s32 = (Uint32 *)src;
778 d8 = (Uint8 *)dst;
779 d16 = (Uint16 *)dst;
780 d32 = (Uint32 *)dst;
781 rshift = format->Rshift;
782 gshift = format->Gshift;
783 bshift = format->Bshift;
784 rloss = format->Rloss;
785 gloss = format->Gloss;
786 bloss = format->Bloss;
787
788 if (source == V4L2_PIX_FMT_RGB444 || source == V4L2_PIX_FMT_RGB24 ||
789 source == V4L2_PIX_FMT_XBGR32) {
790 while (length--) {
791 if (source == V4L2_PIX_FMT_RGB444) {
792 p1 = *s8++;
793 p2 = *s8++;
794 b = p2 << 4;
795 g = p1 & 0xF0;
796 r = p1 << 4;
797 }
798 else if (source == V4L2_PIX_FMT_RGB24) {
799 r = *s8++;
800 g = *s8++;
801 b = *s8++;
802 }
803 else {
804 b = *s8++;
805 g = *s8++;
806 r = *s8++;
807 s8++;
808 }
809
810 v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128; /* V */
811 u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128; /* U */
812 y = (77 * r + 150 * g + 29 * b + 128) >> 8; /* Y */
813 switch (format->BytesPerPixel) {
814 case 1:
815 *d8++ = ((y >> rloss) << rshift) |
816 ((u >> gloss) << gshift) |
817 ((v >> bloss) << bshift);
818 break;
819 case 2:
820 *d16++ = ((y >> rloss) << rshift) |
821 ((u >> gloss) << gshift) |
822 ((v >> bloss) << bshift);
823 break;
824 case 3:
825 *d8++ = v;
826 *d8++ = u;
827 *d8++ = y;
828 break;
829 default:
830 *d32++ = ((y >> rloss) << rshift) |
831 ((u >> gloss) << gshift) |
832 ((v >> bloss) << bshift);
833 break;
834 }
835 }
836 }
837 else { /* for use as stage 2 in bayer to yuv, r and b switched */
838 switch (format->BytesPerPixel) {
839 case 1:
840 while (length--) {
841 r = *s8 >> rshift << rloss;
842 g = *s8 >> gshift << gloss;
843 b = *s8++ >> bshift << bloss;
844 *d8++ =
845 ((((77 * r + 150 * g + 29 * b + 128) >> 8) >> rloss)
846 << rshift) |
847 (((((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128) >>
848 gloss)
849 << gshift) |
850 (((((112 * r - 94 * g - 18 * b + 128) >> 8) + 128) >>
851 bloss)
852 << bshift);
853 }
854 break;
855 case 2:
856 while (length--) {
857 r = *s16 >> rshift << rloss;
858 g = *s16 >> gshift << gloss;
859 b = *s16++ >> bshift << bloss;
860 *d16++ =
861 ((((77 * r + 150 * g + 29 * b + 128) >> 8) >> rloss)
862 << rshift) |
863 (((((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128) >>
864 gloss)
865 << gshift) |
866 (((((112 * r - 94 * g - 18 * b + 128) >> 8) + 128) >>
867 bloss)
868 << bshift);
869 }
870 break;
871 case 3:
872 while (length--) {
873 b = *s8++;
874 g = *s8++;
875 r = *s8++;
876 *d8++ = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
877 *d8++ = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
878 *d8++ = (77 * r + 150 * g + 29 * b + 128) >> 8;
879 }
880 break;
881 default:
882 while (length--) {
883 r = *s32 >> rshift << rloss;
884 g = *s32 >> gshift << gloss;
885 b = *s32++ >> bshift << bloss;
886 *d32++ =
887 ((((77 * r + 150 * g + 29 * b + 128) >> 8) >> rloss)
888 << rshift) |
889 (((((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128) >>
890 gloss)
891 << gshift) |
892 (((((112 * r - 94 * g - 18 * b + 128) >> 8) + 128) >>
893 bloss)
894 << bshift);
895 }
896 break;
897 }
898 }
899 }
900
901 /* Converts from rgb444 (R444) to rgb24 (RGB3) */
902 void
rgb444_to_rgb(const void * src,void * dst,int length,SDL_PixelFormat * format)903 rgb444_to_rgb(const void *src, void *dst, int length, SDL_PixelFormat *format)
904 {
905 Uint8 *s, *d8;
906 Uint16 *d16;
907 Uint32 *d32;
908 Uint8 p1, p2, r, g, b;
909 int rshift, gshift, bshift, rloss, gloss, bloss;
910
911 s = (Uint8 *)src;
912 rshift = format->Rshift;
913 gshift = format->Gshift;
914 bshift = format->Bshift;
915 rloss = format->Rloss;
916 gloss = format->Gloss;
917 bloss = format->Bloss;
918
919 switch (format->BytesPerPixel) {
920 case 1:
921 d8 = (Uint8 *)dst;
922 while (length--) {
923 r = *s << 4;
924 g = *s++ & 0xF0;
925 b = *s++ << 4;
926 *d8++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
927 ((b >> bloss) << bshift);
928 }
929 break;
930 case 2:
931 d16 = (Uint16 *)dst;
932 while (length--) {
933 r = *s << 4;
934 g = *s++ & 0xF0;
935 b = *s++ << 4;
936 *d16++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
937 ((b >> bloss) << bshift);
938 }
939 break;
940 case 3:
941 d8 = (Uint8 *)dst;
942 while (length--) {
943 p1 = *s++;
944 p2 = *s++;
945 *d8++ = p2 << 4; /* blue */
946 *d8++ = p1 & 0xF0; /* green */
947 *d8++ = p1 << 4; /* red */
948 }
949 break;
950 default:
951 d32 = (Uint32 *)dst;
952 while (length--) {
953 r = *s << 4;
954 g = *s++ & 0xF0;
955 b = *s++ << 4;
956 *d32++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
957 ((b >> bloss) << bshift);
958 }
959 break;
960 }
961 }
962
963 /* convert from 4:2:2 YUYV interlaced to RGB */
964 /* colorspace conversion routine from libv4l. Licensed LGPL 2.1
965 (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> */
966 void
yuyv_to_rgb(const void * src,void * dst,int length,SDL_PixelFormat * format)967 yuyv_to_rgb(const void *src, void *dst, int length, SDL_PixelFormat *format)
968 {
969 Uint8 *s, *d8;
970 Uint16 *d16;
971 Uint32 *d32;
972 int i;
973 int r1, g1, b1, r2, b2, g2;
974 int rshift, gshift, bshift, rloss, gloss, bloss, y1, y2, u, v, u1, rg, v1;
975
976 rshift = format->Rshift;
977 gshift = format->Gshift;
978 bshift = format->Bshift;
979 rloss = format->Rloss;
980 gloss = format->Gloss;
981 bloss = format->Bloss;
982
983 d8 = (Uint8 *)dst;
984 d16 = (Uint16 *)dst;
985 d32 = (Uint32 *)dst;
986 i = length >> 1;
987 s = (Uint8 *)src;
988
989 /* yuyv packs 2 pixels into every 4 bytes, sharing the u and v color
990 terms between the 2, with each pixel having a unique y luminance term.
991 Thus, we will operate on 2 pixels at a time. */
992 while (i--) {
993 y1 = *s++;
994 u = *s++;
995 y2 = *s++;
996 v = *s++;
997 /* The lines from here to the switch statement are from libv4l */
998 u1 = (((u - 128) << 7) + (u - 128)) >> 6;
999 rg = (((u - 128) << 1) + (u - 128) + ((v - 128) << 2) +
1000 ((v - 128) << 1)) >>
1001 3;
1002 v1 = (((v - 128) << 1) + (v - 128)) >> 1;
1003
1004 r1 = SAT2(y1 + v1);
1005 g1 = SAT2(y1 - rg);
1006 b1 = SAT2(y1 + u1);
1007
1008 r2 = SAT2(y2 + v1);
1009 g2 = SAT2(y2 - rg);
1010 b2 = SAT2(y2 + u1);
1011
1012 /* choose the right pixel packing for the destination surface depth */
1013 switch (format->BytesPerPixel) {
1014 case 1:
1015 *d8++ = ((r1 >> rloss) << rshift) | ((g1 >> gloss) << gshift) |
1016 ((b1 >> bloss) << bshift);
1017 *d8++ = ((r2 >> rloss) << rshift) | ((g2 >> gloss) << gshift) |
1018 ((b2 >> bloss) << bshift);
1019 break;
1020 case 2:
1021 *d16++ = ((r1 >> rloss) << rshift) |
1022 ((g1 >> gloss) << gshift) | ((b1 >> bloss) << bshift);
1023 *d16++ = ((r2 >> rloss) << rshift) |
1024 ((g2 >> gloss) << gshift) | ((b2 >> bloss) << bshift);
1025 break;
1026 case 3:
1027 *d8++ = b1;
1028 *d8++ = g1;
1029 *d8++ = r1;
1030 *d8++ = b2;
1031 *d8++ = g2;
1032 *d8++ = r2;
1033 break;
1034 default:
1035 *d32++ = ((r1 >> rloss) << rshift) |
1036 ((g1 >> gloss) << gshift) | ((b1 >> bloss) << bshift);
1037 *d32++ = ((r2 >> rloss) << rshift) |
1038 ((g2 >> gloss) << gshift) | ((b2 >> bloss) << bshift);
1039 break;
1040 }
1041 }
1042 }
1043
1044 /* turn yuyv into packed yuv. */
1045 void
yuyv_to_yuv(const void * src,void * dst,int length,SDL_PixelFormat * format)1046 yuyv_to_yuv(const void *src, void *dst, int length, SDL_PixelFormat *format)
1047 {
1048 Uint8 *s, *d8;
1049 Uint8 y1, u, y2, v;
1050 Uint16 *d16;
1051 Uint32 *d32;
1052 int i = length >> 1;
1053 int rshift, gshift, bshift, rloss, gloss, bloss;
1054
1055 rshift = format->Rshift;
1056 gshift = format->Gshift;
1057 bshift = format->Bshift;
1058 rloss = format->Rloss;
1059 gloss = format->Gloss;
1060 bloss = format->Bloss;
1061 s = (Uint8 *)src;
1062
1063 switch (format->BytesPerPixel) {
1064 case 1:
1065 d8 = (Uint8 *)dst;
1066 while (i--) {
1067 y1 = *s++;
1068 u = *s++;
1069 y2 = *s++;
1070 v = *s++;
1071 *d8++ = ((y1 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1072 ((v >> bloss) << bshift);
1073 *d8++ = ((y2 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1074 ((v >> bloss) << bshift);
1075 }
1076 break;
1077 case 2:
1078 d16 = (Uint16 *)dst;
1079 while (i--) {
1080 y1 = *s++;
1081 u = *s++;
1082 y2 = *s++;
1083 v = *s++;
1084 *d16++ = ((y1 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1085 ((v >> bloss) << bshift);
1086 *d16++ = ((y2 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1087 ((v >> bloss) << bshift);
1088 }
1089 break;
1090 case 3:
1091 d8 = (Uint8 *)dst;
1092 while (i--) {
1093 *d8++ = *(s + 3); /* v */
1094 *d8++ = *(s + 1); /* u */
1095 *d8++ = *s; /* y1 */
1096 *d8++ = *(s + 3); /* v */
1097 *d8++ = *(s + 1); /* u */
1098 *d8++ = *(s + 2); /* y2 */
1099 s += 4;
1100 }
1101 break;
1102 default:
1103 d32 = (Uint32 *)dst;
1104 while (i--) {
1105 y1 = *s++;
1106 u = *s++;
1107 y2 = *s++;
1108 v = *s++;
1109 *d32++ = ((y1 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1110 ((v >> bloss) << bshift);
1111 *d32++ = ((y2 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1112 ((v >> bloss) << bshift);
1113 }
1114 break;
1115 }
1116 }
1117
1118 /* cribbed from above, but modified for uyvy ordering */
1119 void
uyvy_to_rgb(const void * src,void * dst,int length,SDL_PixelFormat * format)1120 uyvy_to_rgb(const void *src, void *dst, int length, SDL_PixelFormat *format)
1121 {
1122 Uint8 *s, *d8;
1123 Uint16 *d16;
1124 Uint32 *d32;
1125 int i;
1126 int r1, g1, b1, r2, b2, g2;
1127 int rshift, gshift, bshift, rloss, gloss, bloss, y1, y2, u, v, u1, rg, v1;
1128
1129 rshift = format->Rshift;
1130 gshift = format->Gshift;
1131 bshift = format->Bshift;
1132 rloss = format->Rloss;
1133 gloss = format->Gloss;
1134 bloss = format->Bloss;
1135
1136 d8 = (Uint8 *)dst;
1137 d16 = (Uint16 *)dst;
1138 d32 = (Uint32 *)dst;
1139 i = length >> 1;
1140 s = (Uint8 *)src;
1141
1142 /* yuyv packs 2 pixels into every 4 bytes, sharing the u and v color
1143 terms between the 2, with each pixel having a unique y luminance term.
1144 Thus, we will operate on 2 pixels at a time. */
1145 while (i--) {
1146 u = *s++;
1147 y1 = *s++;
1148 v = *s++;
1149 y2 = *s++;
1150
1151 /* The lines from here to the switch statement are from libv4l */
1152 u1 = (((u - 128) << 7) + (u - 128)) >> 6;
1153 rg = (((u - 128) << 1) + (u - 128) + ((v - 128) << 2) +
1154 ((v - 128) << 1)) >>
1155 3;
1156 v1 = (((v - 128) << 1) + (v - 128)) >> 1;
1157
1158 r1 = SAT2(y1 + v1);
1159 g1 = SAT2(y1 - rg);
1160 b1 = SAT2(y1 + u1);
1161
1162 r2 = SAT2(y2 + v1);
1163 g2 = SAT2(y2 - rg);
1164 b2 = SAT2(y2 + u1);
1165
1166 /* choose the right pixel packing for the destination surface depth */
1167 switch (format->BytesPerPixel) {
1168 case 1:
1169 *d8++ = ((r1 >> rloss) << rshift) | ((g1 >> gloss) << gshift) |
1170 ((b1 >> bloss) << bshift);
1171 *d8++ = ((r2 >> rloss) << rshift) | ((g2 >> gloss) << gshift) |
1172 ((b2 >> bloss) << bshift);
1173 break;
1174 case 2:
1175 *d16++ = ((r1 >> rloss) << rshift) |
1176 ((g1 >> gloss) << gshift) | ((b1 >> bloss) << bshift);
1177 *d16++ = ((r2 >> rloss) << rshift) |
1178 ((g2 >> gloss) << gshift) | ((b2 >> bloss) << bshift);
1179 break;
1180 case 3:
1181 *d8++ = b1;
1182 *d8++ = g1;
1183 *d8++ = r1;
1184 *d8++ = b2;
1185 *d8++ = g2;
1186 *d8++ = r2;
1187 break;
1188 default:
1189 *d32++ = ((r1 >> rloss) << rshift) |
1190 ((g1 >> gloss) << gshift) | ((b1 >> bloss) << bshift);
1191 *d32++ = ((r2 >> rloss) << rshift) |
1192 ((g2 >> gloss) << gshift) | ((b2 >> bloss) << bshift);
1193 break;
1194 }
1195 }
1196 }
1197 /* turn uyvy into packed yuv. */
1198 void
uyvy_to_yuv(const void * src,void * dst,int length,SDL_PixelFormat * format)1199 uyvy_to_yuv(const void *src, void *dst, int length, SDL_PixelFormat *format)
1200 {
1201 Uint8 *s, *d8;
1202 Uint8 y1, u, y2, v;
1203 Uint16 *d16;
1204 Uint32 *d32;
1205 int i = length >> 1;
1206 int rshift, gshift, bshift, rloss, gloss, bloss;
1207
1208 rshift = format->Rshift;
1209 gshift = format->Gshift;
1210 bshift = format->Bshift;
1211 rloss = format->Rloss;
1212 gloss = format->Gloss;
1213 bloss = format->Bloss;
1214 s = (Uint8 *)src;
1215
1216 switch (format->BytesPerPixel) {
1217 case 1:
1218 d8 = (Uint8 *)dst;
1219 while (i--) {
1220 u = *s++;
1221 y1 = *s++;
1222 v = *s++;
1223 y2 = *s++;
1224 *d8++ = ((y1 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1225 ((v >> bloss) << bshift);
1226 *d8++ = ((y2 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1227 ((v >> bloss) << bshift);
1228 }
1229 break;
1230 case 2:
1231 d16 = (Uint16 *)dst;
1232 while (i--) {
1233 u = *s++;
1234 y1 = *s++;
1235 v = *s++;
1236 y2 = *s++;
1237 *d16++ = ((y1 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1238 ((v >> bloss) << bshift);
1239 *d16++ = ((y2 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1240 ((v >> bloss) << bshift);
1241 }
1242 break;
1243 case 3:
1244 d8 = (Uint8 *)dst;
1245 while (i--) {
1246 *d8++ = *(s + 2); /* v */
1247 *d8++ = *s; /* u */
1248 *d8++ = *(s + 1); /* y1 */
1249 *d8++ = *(s + 2); /* v */
1250 *d8++ = *s; /* u */
1251 *d8++ = *(s + 3); /* y2 */
1252 s += 4;
1253 }
1254 break;
1255 default:
1256 d32 = (Uint32 *)dst;
1257 while (i--) {
1258 y1 = *s++;
1259 u = *s++;
1260 y2 = *s++;
1261 v = *s++;
1262 *d32++ = ((y1 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1263 ((v >> bloss) << bshift);
1264 *d32++ = ((y2 >> rloss) << rshift) | ((u >> gloss) << gshift) |
1265 ((v >> bloss) << bshift);
1266 }
1267 break;
1268 }
1269 }
1270
1271 /* Converts from 8 bit Bayer (BA81) to rgb24 (RGB3), based on:
1272 * Sonix SN9C101 based webcam basic I/F routines
1273 * Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp>
1274 *
1275 * Redistribution and use in source and binary forms, with or without
1276 * modification, are permitted provided that the following conditions
1277 * are met:
1278 * 1. Redistributions of source code must retain the above copyright
1279 * notice, this list of conditions and the following disclaimer.
1280 * 2. Redistributions in binary form must reproduce the above copyright
1281 * notice, this list of conditions and the following disclaimer in the
1282 * documentation and/or other materials provided with the distribution.
1283 *
1284 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1285 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1286 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1287 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1288 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1289 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1290 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1291 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1292 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1293 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1294 * SUCH DAMAGE.
1295 */
1296 /* TODO: Certainly not the most efficient way of doing this conversion. */
1297 void
sbggr8_to_rgb(const void * src,void * dst,int width,int height,SDL_PixelFormat * format)1298 sbggr8_to_rgb(const void *src, void *dst, int width, int height,
1299 SDL_PixelFormat *format)
1300 {
1301 Uint8 *rawpt, *d8;
1302 Uint16 *d16;
1303 Uint32 *d32;
1304 Uint8 r, g, b;
1305 int rshift, gshift, bshift, rloss, gloss, bloss;
1306 int i = width * height;
1307 rawpt = (Uint8 *)src;
1308 rshift = format->Rshift;
1309 gshift = format->Gshift;
1310 bshift = format->Bshift;
1311 rloss = format->Rloss;
1312 gloss = format->Gloss;
1313 bloss = format->Bloss;
1314
1315 d8 = (Uint8 *)dst;
1316 d16 = (Uint16 *)dst;
1317 d32 = (Uint32 *)dst;
1318
1319 while (i--) {
1320 if ((i / width) % 2 == 0) {
1321 /* even row (BGBGBGBG)*/
1322 if ((i % 2) == 0) {
1323 /* B */
1324 if ((i > width) && ((i % width) > 0)) {
1325 b = *rawpt; /* B */
1326 g = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt + width) +
1327 *(rawpt - width)) /
1328 4; /* G */
1329 r = (*(rawpt - width - 1) + *(rawpt - width + 1) +
1330 *(rawpt + width - 1) + *(rawpt + width + 1)) /
1331 4; /* R */
1332 }
1333 else {
1334 /* first line or left column */
1335 b = *rawpt; /* B */
1336 g = (*(rawpt + 1) + *(rawpt + width)) / 2; /* G */
1337 r = *(rawpt + width + 1); /* R */
1338 }
1339 }
1340 else {
1341 /* (B)G */
1342 if ((i > width) && ((i % width) < (width - 1))) {
1343 b = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* B */
1344 g = *rawpt; /* G */
1345 r = (*(rawpt + width) + *(rawpt - width)) / 2; /* R */
1346 }
1347 else {
1348 /* first line or right column */
1349 b = *(rawpt - 1); /* B */
1350 g = *rawpt; /* G */
1351 r = *(rawpt + width); /* R */
1352 }
1353 }
1354 }
1355 else {
1356 /* odd row (GRGRGRGR) */
1357 if ((i % 2) == 0) {
1358 /* G(R) */
1359 if ((i < (width * (height - 1))) && ((i % width) > 0)) {
1360 b = (*(rawpt + width) + *(rawpt - width)) / 2; /* B */
1361 g = *rawpt; /* G */
1362 r = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* R */
1363 }
1364 else {
1365 /* bottom line or left column */
1366 b = *(rawpt - width); /* B */
1367 g = *rawpt; /* G */
1368 r = *(rawpt + 1); /* R */
1369 }
1370 }
1371 else {
1372 /* R */
1373 if (i < (width * (height - 1)) &&
1374 ((i % width) < (width - 1))) {
1375 b = (*(rawpt - width - 1) + *(rawpt - width + 1) +
1376 *(rawpt + width - 1) + *(rawpt + width + 1)) /
1377 4; /* B */
1378 g = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt - width) +
1379 *(rawpt + width)) /
1380 4; /* G */
1381 r = *rawpt; /* R */
1382 }
1383 else {
1384 /* bottom line or right column */
1385 b = *(rawpt - width - 1); /* B */
1386 g = (*(rawpt - 1) + *(rawpt - width)) / 2; /* G */
1387 r = *rawpt; /* R */
1388 }
1389 }
1390 }
1391 rawpt++;
1392 switch (format->BytesPerPixel) {
1393 case 1:
1394 *d8++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
1395 ((b >> bloss) << bshift);
1396 break;
1397 case 2:
1398 *d16++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
1399 ((b >> bloss) << bshift);
1400 break;
1401 case 3:
1402 *d8++ = b;
1403 *d8++ = g;
1404 *d8++ = r;
1405 break;
1406 default:
1407 *d32++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) |
1408 ((b >> bloss) << bshift);
1409 break;
1410 }
1411 }
1412 }
1413
1414 /* convert from YUV 4:2:0 (YU12) to RGB24 */
1415 /* based on v4lconvert_yuv420_to_rgb24 in libv4l (C) 2008 Hans de Goede. LGPL
1416 */
1417 void
yuv420_to_rgb(const void * src,void * dst,int width,int height,SDL_PixelFormat * format)1418 yuv420_to_rgb(const void *src, void *dst, int width, int height,
1419 SDL_PixelFormat *format)
1420 {
1421 int rshift, gshift, bshift, rloss, gloss, bloss, i, j, u1, v1, rg, y;
1422 const Uint8 *y1, *y2, *u, *v;
1423 Uint8 *d8_1, *d8_2;
1424 Uint16 *d16_1, *d16_2;
1425 Uint32 *d32_1, *d32_2;
1426
1427 rshift = format->Rshift;
1428 gshift = format->Gshift;
1429 bshift = format->Bshift;
1430 rloss = format->Rloss;
1431 gloss = format->Gloss;
1432 bloss = format->Bloss;
1433
1434 /* see http://en.wikipedia.org/wiki/YUV for an explanation of YUV420 */
1435 y1 = (Uint8 *)src;
1436 y2 = y1 + width;
1437 u = y1 + width * height;
1438 v = u + (width * height) / 4;
1439 j = height / 2;
1440 /* prepare the destination pointers for different surface depths. */
1441 d8_1 = (Uint8 *)dst;
1442 /* the following is because d8 used for both 8 and 24 bit surfaces */
1443 d8_2 = d8_1 + (format->BytesPerPixel == 3 ? width * 3 : 3);
1444 d16_1 = (Uint16 *)dst;
1445 d16_2 = d16_1 + width;
1446 d32_1 = (Uint32 *)dst;
1447 d32_2 = d32_1 + width;
1448
1449 /* for the sake of speed, the nested while loops are inside of the switch
1450 statement for the different surface bit depths */
1451 switch (format->BytesPerPixel) {
1452 case 1:
1453 while (j--) {
1454 i = width / 2;
1455 while (i--) {
1456 /* These formulas are from libv4l */
1457 u1 = (((*u - 128) << 7) + (*u - 128)) >> 6;
1458 rg = (((*u - 128) << 1) + (*u - 128) + ((*v - 128) << 2) +
1459 ((*v - 128) << 1)) >>
1460 3;
1461 v1 = (((*v - 128) << 1) + (*v - 128)) >> 1;
1462 u++;
1463 v++;
1464 /* do the pixels on row 1 */
1465 y = *y1++;
1466 *d8_1++ = ((SAT2(y + v1) >> rloss) << rshift) |
1467 ((SAT2(y - rg) >> gloss) << gshift) |
1468 ((SAT2(y + u1) >> bloss) << bshift);
1469 y = *y1++;
1470 *d8_1++ = ((SAT2(y + v1) >> rloss) << rshift) |
1471 ((SAT2(y - rg) >> gloss) << gshift) |
1472 ((SAT2(y + u1) >> bloss) << bshift);
1473 /* do the pixels on row 2 */
1474 y = *y2++;
1475 *d8_2++ = ((SAT2(y + v1) >> rloss) << rshift) |
1476 ((SAT2(y - rg) >> gloss) << gshift) |
1477 ((SAT2(y + u1) >> bloss) << bshift);
1478 y = *y2++;
1479 *d8_2++ = ((SAT2(y + v1) >> rloss) << rshift) |
1480 ((SAT2(y - rg) >> gloss) << gshift) |
1481 ((SAT2(y + u1) >> bloss) << bshift);
1482 }
1483 /* y2 is at the beginning of a new row, make it the new row 1
1484 */
1485 y1 = y2;
1486 /* and make row 2 one row further */
1487 y2 += width;
1488 d8_1 = d8_2;
1489 d8_2 += width;
1490 }
1491 break;
1492 case 2:
1493 while (j--) {
1494 i = width / 2;
1495 while (i--) {
1496 /* These formulas are from libv4l */
1497 u1 = (((*u - 128) << 7) + (*u - 128)) >> 6;
1498 rg = (((*u - 128) << 1) + (*u - 128) + ((*v - 128) << 2) +
1499 ((*v - 128) << 1)) >>
1500 3;
1501 v1 = (((*v - 128) << 1) + (*v - 128)) >> 1;
1502 u++;
1503 v++;
1504 /* do the pixels on row 1 */
1505 y = *y1++;
1506 *d16_1++ = ((SAT2(y + v1) >> rloss) << rshift) |
1507 ((SAT2(y - rg) >> gloss) << gshift) |
1508 ((SAT2(y + u1) >> bloss) << bshift);
1509 y = *y1++;
1510 *d16_1++ = ((SAT2(y + v1) >> rloss) << rshift) |
1511 ((SAT2(y - rg) >> gloss) << gshift) |
1512 ((SAT2(y + u1) >> bloss) << bshift);
1513 /* do the pixels on row 2 */
1514 y = *y2++;
1515 *d16_2++ = ((SAT2(y + v1) >> rloss) << rshift) |
1516 ((SAT2(y - rg) >> gloss) << gshift) |
1517 ((SAT2(y + u1) >> bloss) << bshift);
1518 y = *y2++;
1519 *d16_2++ = ((SAT2(y + v1) >> rloss) << rshift) |
1520 ((SAT2(y - rg) >> gloss) << gshift) |
1521 ((SAT2(y + u1) >> bloss) << bshift);
1522 }
1523 /* y2 is at the beginning of a new row, make it the new row 1
1524 */
1525 y1 = y2;
1526 /* and make row 2 one row further */
1527 y2 += width;
1528 d16_1 = d16_2;
1529 d16_2 += width;
1530 }
1531 break;
1532 case 3:
1533 while (j--) {
1534 i = width / 2;
1535 while (i--) {
1536 /* These formulas are from libv4l */
1537 u1 = (((*u - 128) << 7) + (*u - 128)) >> 6;
1538 rg = (((*u - 128) << 1) + (*u - 128) + ((*v - 128) << 2) +
1539 ((*v - 128) << 1)) >>
1540 3;
1541 v1 = (((*v - 128) << 1) + (*v - 128)) >> 1;
1542 u++;
1543 v++;
1544 /* do the pixels on row 1 */
1545 y = *y1++;
1546 *d8_1++ = SAT2(y + u1);
1547 *d8_1++ = SAT2(y - rg);
1548 *d8_1++ = SAT2(y + v1);
1549 y = *y1++;
1550 *d8_1++ = SAT2(y + u1);
1551 *d8_1++ = SAT2(y - rg);
1552 *d8_1++ = SAT2(y + v1);
1553 /* do the pixels on row 2 */
1554 y = *y2++;
1555 *d8_2++ = SAT2(y + u1);
1556 *d8_2++ = SAT2(y - rg);
1557 *d8_2++ = SAT2(y + v1);
1558 y = *y2++;
1559 *d8_2++ = SAT2(y + u1);
1560 *d8_2++ = SAT2(y - rg);
1561 *d8_2++ = SAT2(y + v1);
1562 }
1563 /* y2 is at the beginning of a new row, make it the new row 1
1564 */
1565 y1 = y2;
1566 /* and make row 2 one row further */
1567 y2 += width;
1568 d8_1 = d8_2;
1569 /* since it is 3 bytes per pixel */
1570 d8_2 += width * 3;
1571 }
1572 break;
1573 default:
1574 while (j--) {
1575 i = width / 2;
1576 while (i--) {
1577 /* These formulas are from libv4l */
1578 u1 = (((*u - 128) << 7) + (*u - 128)) >> 6;
1579 rg = (((*u - 128) << 1) + (*u - 128) + ((*v - 128) << 2) +
1580 ((*v - 128) << 1)) >>
1581 3;
1582 v1 = (((*v - 128) << 1) + (*v - 128)) >> 1;
1583 u++;
1584 v++;
1585 /* do the pixels on row 1 */
1586 y = *y1++;
1587 *d32_1++ = ((SAT2(y + v1) >> rloss) << rshift) |
1588 ((SAT2(y - rg) >> gloss) << gshift) |
1589 ((SAT2(y + u1) >> bloss) << bshift);
1590 y = *y1++;
1591 *d32_1++ = ((SAT2(y + v1) >> rloss) << rshift) |
1592 ((SAT2(y - rg) >> gloss) << gshift) |
1593 ((SAT2(y + u1) >> bloss) << bshift);
1594 /* do the pixels on row 2 */
1595 y = *y2++;
1596 *d32_2++ = ((SAT2(y + v1) >> rloss) << rshift) |
1597 ((SAT2(y - rg) >> gloss) << gshift) |
1598 ((SAT2(y + u1) >> bloss) << bshift);
1599 y = *y2++;
1600 *d32_2++ = ((SAT2(y + v1) >> rloss) << rshift) |
1601 ((SAT2(y - rg) >> gloss) << gshift) |
1602 ((SAT2(y + u1) >> bloss) << bshift);
1603 }
1604 /* y2 is at the beginning of a new row, make it the new row 1
1605 */
1606 y1 = y2;
1607 /* and make row 2 one row further */
1608 y2 += width;
1609 d32_1 = d32_2;
1610 d32_2 += width;
1611 }
1612 break;
1613 }
1614 }
1615
1616 /* turn yuv420 into packed yuv. */
1617 void
yuv420_to_yuv(const void * src,void * dst,int width,int height,SDL_PixelFormat * format)1618 yuv420_to_yuv(const void *src, void *dst, int width, int height,
1619 SDL_PixelFormat *format)
1620 {
1621 const Uint8 *y1, *y2, *u, *v;
1622 Uint8 *d8_1, *d8_2;
1623 Uint16 *d16_1, *d16_2;
1624 Uint32 *d32_1, *d32_2;
1625 int rshift, gshift, bshift, rloss, gloss, bloss, j, i;
1626
1627 rshift = format->Rshift;
1628 gshift = format->Gshift;
1629 bshift = format->Bshift;
1630 rloss = format->Rloss;
1631 gloss = format->Gloss;
1632 bloss = format->Bloss;
1633
1634 d8_1 = (Uint8 *)dst;
1635 d8_2 = d8_1 + (format->BytesPerPixel == 3 ? width * 3 : 3);
1636 d16_1 = (Uint16 *)dst;
1637 d16_2 = d16_1 + width;
1638 d32_1 = (Uint32 *)dst;
1639 d32_2 = d32_1 + width;
1640 y1 = (Uint8 *)src;
1641 y2 = y1 + width;
1642 u = y1 + width * height;
1643 v = u + (width * height) / 4;
1644 j = height / 2;
1645
1646 switch (format->BytesPerPixel) {
1647 case 1:
1648 while (j--) {
1649 i = width / 2;
1650 while (i--) {
1651 *d8_1++ = ((*y1++ >> rloss) << rshift) |
1652 ((*u >> gloss) << gshift) |
1653 ((*v >> bloss) << bshift);
1654 *d8_1++ = ((*y1++ >> rloss) << rshift) |
1655 ((*u >> gloss) << gshift) |
1656 ((*v >> bloss) << bshift);
1657 *d8_2++ = ((*y2++ >> rloss) << rshift) |
1658 ((*u >> gloss) << gshift) |
1659 ((*v >> bloss) << bshift);
1660 *d8_2++ = ((*y2++ >> rloss) << rshift) |
1661 ((*u++ >> gloss) << gshift) |
1662 ((*v++ >> bloss) << bshift);
1663 }
1664 y1 = y2;
1665 y2 += width;
1666 d8_1 = d8_2;
1667 d8_2 += width;
1668 }
1669 break;
1670 case 2:
1671 while (j--) {
1672 i = width / 2;
1673 while (i--) {
1674 *d16_1++ = ((*y1++ >> rloss) << rshift) |
1675 ((*u >> gloss) << gshift) |
1676 ((*v >> bloss) << bshift);
1677 *d16_1++ = ((*y1++ >> rloss) << rshift) |
1678 ((*u >> gloss) << gshift) |
1679 ((*v >> bloss) << bshift);
1680 *d16_2++ = ((*y2++ >> rloss) << rshift) |
1681 ((*u >> gloss) << gshift) |
1682 ((*v >> bloss) << bshift);
1683 *d16_2++ = ((*y2++ >> rloss) << rshift) |
1684 ((*u++ >> gloss) << gshift) |
1685 ((*v++ >> bloss) << bshift);
1686 }
1687 y1 = y2;
1688 y2 += width;
1689 d16_1 = d16_2;
1690 d16_2 += width;
1691 }
1692 break;
1693 case 3:
1694 while (j--) {
1695 i = width / 2;
1696 while (i--) {
1697 *d8_1++ = *v;
1698 *d8_1++ = *u;
1699 *d8_1++ = *y1++;
1700 *d8_1++ = *v;
1701 *d8_1++ = *u;
1702 *d8_1++ = *y1++;
1703 *d8_2++ = *v;
1704 *d8_2++ = *u;
1705 *d8_2++ = *y2++;
1706 *d8_2++ = *v++;
1707 *d8_2++ = *u++;
1708 *d8_2++ = *y2++;
1709 }
1710 y1 = y2;
1711 y2 += width;
1712 d8_1 = d8_2;
1713 d8_2 += width * 3;
1714 }
1715 break;
1716 default:
1717 while (j--) {
1718 i = width / 2;
1719 while (i--) {
1720 *d32_1++ = ((*y1++ >> rloss) << rshift) |
1721 ((*u >> gloss) << gshift) |
1722 ((*v >> bloss) << bshift);
1723 *d32_1++ = ((*y1++ >> rloss) << rshift) |
1724 ((*u >> gloss) << gshift) |
1725 ((*v >> bloss) << bshift);
1726 *d32_2++ = ((*y2++ >> rloss) << rshift) |
1727 ((*u >> gloss) << gshift) |
1728 ((*v >> bloss) << bshift);
1729 *d32_2++ = ((*y2++ >> rloss) << rshift) |
1730 ((*u++ >> gloss) << gshift) |
1731 ((*v++ >> bloss) << bshift);
1732 }
1733 y1 = y2;
1734 y2 += width;
1735 d32_1 = d32_2;
1736 d32_2 += width;
1737 }
1738 break;
1739 }
1740 }
1741
1742 /*
1743 * Python API stuff
1744 */
1745
1746 /* Camera class definition */
1747 PyMethodDef cameraobj_builtins[] = {
1748 {"start", (PyCFunction)camera_start, METH_NOARGS, DOC_CAMERASTART},
1749 {"stop", (PyCFunction)camera_stop, METH_NOARGS, DOC_CAMERASTOP},
1750 {"get_controls", (PyCFunction)camera_get_controls, METH_NOARGS,
1751 DOC_CAMERAGETCONTROLS},
1752 {"set_controls", (PyCFunction)camera_set_controls,
1753 METH_VARARGS | METH_KEYWORDS, DOC_CAMERASETCONTROLS},
1754 {"get_size", (PyCFunction)camera_get_size, METH_NOARGS, DOC_CAMERAGETSIZE},
1755 {"query_image", (PyCFunction)camera_query_image, METH_NOARGS,
1756 DOC_CAMERAQUERYIMAGE},
1757 {"get_image", (PyCFunction)camera_get_image, METH_VARARGS,
1758 DOC_CAMERAGETIMAGE},
1759 {"get_raw", (PyCFunction)camera_get_raw, METH_NOARGS, DOC_CAMERAGETRAW},
1760 {NULL, NULL, 0, NULL}};
1761
1762 void
camera_dealloc(PyObject * self)1763 camera_dealloc(PyObject *self)
1764 {
1765 #if defined(PYGAME_WINDOWS_CAMERA)
1766 if (((pgCameraObject *)self)->open) {
1767 windows_close_device((pgCameraObject *)self);
1768 }
1769 windows_dealloc_device((pgCameraObject *)self);
1770 #else
1771 free(((pgCameraObject *)self)->device_name);
1772 #endif
1773 PyObject_DEL(self);
1774 }
1775 /*
1776 PyObject* camera_getattr(PyObject* self, char* attrname) {
1777 return Py_FindMethod(cameraobj_builtins, self, attrname);
1778 }
1779 */
1780 PyTypeObject pgCamera_Type = {
1781 PyVarObject_HEAD_INIT(NULL, 0) "Camera",
1782 sizeof(pgCameraObject),
1783 0,
1784 camera_dealloc,
1785 0,
1786 0, /*camera_getattr */
1787 NULL, /*setattr*/
1788 NULL, /*compare*/
1789 NULL, /*repr*/
1790 NULL, /*as_number*/
1791 NULL, /*as_sequence*/
1792 NULL, /*as_mapping*/
1793 (hashfunc)NULL, /*hash*/
1794 (ternaryfunc)NULL, /*call*/
1795 (reprfunc)NULL, /*str*/
1796 0L,
1797 0L,
1798 0L,
1799 0L,
1800 DOC_PYGAMECAMERACAMERA, /* Documentation string */
1801 0, /* tp_traverse */
1802 0, /* tp_clear */
1803 0, /* tp_richcompare */
1804 0, /* tp_weaklistoffset */
1805 0, /* tp_iter */
1806 0, /* tp_iternext */
1807 cameraobj_builtins, /* tp_methods */
1808 0, /* tp_members */
1809 0, /* tp_getset */
1810 0, /* tp_base */
1811 0, /* tp_dict */
1812 0, /* tp_descr_get */
1813 0, /* tp_descr_set */
1814 0, /* tp_dictoffset */
1815 0, /* tp_init */
1816 0, /* tp_alloc */
1817 0, /* tp_new */
1818 };
1819
1820 PyObject *
Camera(pgCameraObject * self,PyObject * arg)1821 Camera(pgCameraObject *self, PyObject *arg)
1822 {
1823 #if defined(__unix__)
1824 int w, h;
1825 char *dev_name = NULL;
1826 char *color = NULL;
1827 pgCameraObject *cameraobj;
1828
1829 w = DEFAULT_WIDTH;
1830 h = DEFAULT_HEIGHT;
1831
1832 if (!PyArg_ParseTuple(arg, "s|(ii)s", &dev_name, &w, &h, &color))
1833 return NULL;
1834
1835 cameraobj = PyObject_NEW(pgCameraObject, &pgCamera_Type);
1836
1837 if (cameraobj) {
1838 cameraobj->device_name =
1839 (char *)malloc((strlen(dev_name) + 1) * sizeof(char));
1840 if (!cameraobj->device_name) {
1841 Py_DECREF(cameraobj);
1842 return PyErr_NoMemory();
1843 }
1844 strcpy(cameraobj->device_name, dev_name);
1845 cameraobj->camera_type = 0;
1846 cameraobj->pixelformat = 0;
1847 if (color) {
1848 if (!strcmp(color, "YUV")) {
1849 cameraobj->color_out = YUV_OUT;
1850 }
1851 else if (!strcmp(color, "HSV")) {
1852 cameraobj->color_out = HSV_OUT;
1853 }
1854 else {
1855 cameraobj->color_out = RGB_OUT;
1856 }
1857 }
1858 else {
1859 cameraobj->color_out = RGB_OUT;
1860 }
1861 cameraobj->buffers = NULL;
1862 cameraobj->n_buffers = 0;
1863 cameraobj->width = w;
1864 cameraobj->height = h;
1865 cameraobj->size = 0;
1866 cameraobj->hflip = 0;
1867 cameraobj->vflip = 0;
1868 cameraobj->brightness = 0;
1869 cameraobj->fd = -1;
1870 }
1871
1872 return (PyObject *)cameraobj;
1873 #elif defined(PYGAME_WINDOWS_CAMERA)
1874 pgCameraObject *cameraobj;
1875 PyObject *name_obj = NULL;
1876 WCHAR *dev_name = NULL;
1877 int w, h;
1878 char *color = NULL;
1879 IMFActivate *p = NULL;
1880
1881 w = DEFAULT_WIDTH;
1882 h = DEFAULT_HEIGHT;
1883
1884 if (!PyArg_ParseTuple(arg, "O|(ii)s", &name_obj, &w, &h, &color))
1885 return NULL;
1886
1887 /* needs to be freed with PyMem_Free later */
1888 dev_name = PyUnicode_AsWideCharString(name_obj, NULL);
1889
1890 p = windows_device_from_name(dev_name);
1891
1892 if (!p) {
1893 return RAISE(PyExc_ValueError,
1894 "Couldn't find a camera with that name");
1895 }
1896
1897 cameraobj = PyObject_NEW(pgCameraObject, &pgCamera_Type);
1898
1899 if (color) {
1900 if (!strcmp(color, "YUV")) {
1901 cameraobj->color_out = YUV_OUT;
1902 }
1903 else if (!strcmp(color, "HSV")) {
1904 cameraobj->color_out = HSV_OUT;
1905 }
1906 else {
1907 cameraobj->color_out = RGB_OUT;
1908 }
1909 }
1910 else {
1911 cameraobj->color_out = RGB_OUT;
1912 }
1913
1914 cameraobj->device_name = dev_name;
1915 cameraobj->width = w;
1916 cameraobj->height = h;
1917 cameraobj->open = 0;
1918 cameraobj->hflip = 0;
1919 cameraobj->vflip = 0;
1920 cameraobj->last_vflip = 0;
1921
1922 cameraobj->raw_buf = NULL;
1923 cameraobj->buf = NULL;
1924 cameraobj->t_handle = NULL;
1925
1926 if (!windows_init_device(self)) {
1927 return NULL;
1928 }
1929
1930 return (PyObject *)cameraobj;
1931 #endif
1932 }
1933
1934 /* Camera module definition */
1935 PyMethodDef camera_builtins[] = {
1936 {"colorspace", surf_colorspace, METH_VARARGS, DOC_PYGAMECAMERACOLORSPACE},
1937 {"list_cameras", list_cameras, METH_NOARGS, DOC_PYGAMECAMERALISTCAMERAS},
1938 {"Camera", (PyCFunction)Camera, METH_VARARGS, DOC_PYGAMECAMERACAMERA},
1939 {NULL, NULL, 0, NULL}};
1940
MODINIT_DEFINE(_camera)1941 MODINIT_DEFINE(_camera)
1942 {
1943 PyObject *module;
1944 /* imported needed apis; Do this first so if there is an error
1945 * the module is not loaded.
1946 */
1947
1948 static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT,
1949 "_camera",
1950 DOC_PYGAMECAMERA,
1951 -1,
1952 camera_builtins,
1953 NULL,
1954 NULL,
1955 NULL,
1956 NULL};
1957
1958 import_pygame_base();
1959 if (PyErr_Occurred()) {
1960 MODINIT_ERROR;
1961 }
1962 import_pygame_surface();
1963 if (PyErr_Occurred()) {
1964 MODINIT_ERROR;
1965 }
1966
1967 /* type preparation */
1968 // PyType_Init(pgCamera_Type);
1969 pgCamera_Type.tp_new = PyType_GenericNew;
1970 if (PyType_Ready(&pgCamera_Type) < 0) {
1971 MODINIT_ERROR;
1972 }
1973
1974 /* create the module */
1975 module = PyModule_Create(&_module);
1976
1977 Py_INCREF(&pgCamera_Type);
1978 PyModule_AddObject(module, "CameraType", (PyObject *)&pgCamera_Type);
1979
1980 MODINIT_RETURN(module);
1981 }
1982