Commits

illume committed d30a1c6

moved camera.c _camera.c . created a lib/camera.py

  • Participants
  • Parent commits 8dc6814

Comments (0)

Files changed (5)

 _numericsndarray src/_numericsndarray.c $(SDL) $(MIXER) $(DEBUG)
 movie src/movie.c $(SDL) $(SMPEG) $(DEBUG)
 scrap src/scrap.c $(SDL) $(SCRAP) $(DEBUG)
-camera src/camera.c src/camera_v4l2.c src/camera_v4l.c $(SDL) $(DEBUG)
+_camera src/_camera.c src/camera_v4l2.c src/camera_v4l.c $(SDL) $(DEBUG)
 pypm src/pypm.c $(SDL) $(PORTMIDI) $(PORTTIME) $(DEBUG)
 
 #experimental new movie movie. requires libavcodec and libavformat.

File examples/camera.py

        # if you don't want to tie the framerate to the camera, you can check and
        # see if the camera has an image ready.  note that while this works
        # on most cameras, some will never return true.
-       if self.camera.query_image():
+       if 0 and self.camera.query_image():
            # capture an image
+
            self.snapshot = self.camera.get_image(self.snapshot)
+       self.snapshot = self.camera.get_image(self.snapshot)
+       #self.snapshot = self.camera.get_image()
 
        # blit it to the display surface.  simple!
        self.display.blit(self.snapshot, (0,0))
 
            self.get_and_flip()
            self.clock.tick()
-#           print self.clock.get_fps()
+           print self.clock.get_fps()
 
 def main():
     pygame.init()
+    pygame.camera.init()
     VideoCapturePlayer().main()
     pygame.quit()
 

File lib/camera.py

+
+
+
+def init():
+    global list_cameras, Camera, colorspace
+
+
+    # TODO: select the camera module to import here.
+    import _camera
+    list_cameras = _camera.list_cameras
+    Camera = _camera.Camera
+    colorspace = _camera.colorspace
+
+
+    pass
+
+
+def quit():
+    pass
+ 
+
+
+def list_cameras():
+    """
+    """
+    raise NotImplementedError()
+
+
+class Camera:
+
+    def __init__(self, device =0, size = (320, 200), mode = "RGB"):
+        """
+        """
+        raise NotImplementedError()
+
+    def set_resolution(self, width, height):
+        """Sets the capture resolution. (without dialog)
+        """
+        pass
+
+    def start(self):
+        """
+        """
+
+    def stop(self):
+        """
+        """
+
+    def get_buffer(self):
+        """
+        """
+
+
+    def get_image(self, dest_surf = None):
+        """
+        """
+
+    def get_surface(self, dest_surf = None):
+        """
+        """
+
+
+
+if __name__ == "__main__":
+
+    # try and use this camera stuff with the pygame camera example.
+    import pygame.examples.camera
+
+    #pygame.camera.Camera = Camera
+    #pygame.camera.list_cameras = list_cameras
+    pygame.examples.camera.main()
+
+    
+

File src/_camera.c

+/*
+  pygame - Python Game Library
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public
+  License along with this library; if not, write to the Free
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  
+*/
+
+/*
+ * Camera - webcam support for pygame
+ * Author: Nirav Patel
+ *
+ * This module allows for use of v4l2 webcams in pygame.  The code is written
+ * such that adding support for v4l or vfw cameras should be possible without
+ * much modification of existing functions.  v4l2 functions are kept seperate
+ * from functions available to pygame users and generic functions like
+ * colorspace conversion.
+ *
+ * There is currently support for cameras that support MMAP and use pixelformats
+ * of RGB24, RGB444, YUYV, SBGGR8, and YUV420.  To add support for additional
+ * pixelformats, add them to v4l2_init_device and v4l2_process_image, and add
+ * functions to convert the format to packed RGB, YUV, and HSV.
+ */
+ 
+#include "camera.h"
+
+#if defined(__unix__)
+#else
+    #define V4L2_PIX_FMT_RGB24 1
+    #define V4L2_PIX_FMT_RGB444 1
+#endif
+
+/* functions available to pygame users */
+PyObject* surf_colorspace (PyObject* self, PyObject* arg);
+PyObject* list_cameras (PyObject* self, PyObject* arg);
+PyObject* camera_start (PyCameraObject* self);
+PyObject* camera_stop (PyCameraObject* self);
+PyObject* camera_get_controls (PyCameraObject* self);
+PyObject* camera_set_controls (PyCameraObject* self, PyObject* arg, PyObject *kwds);
+PyObject* camera_get_size (PyCameraObject* self);
+PyObject* camera_query_image (PyCameraObject* self);
+PyObject* camera_get_image (PyCameraObject* self, PyObject* arg);
+PyObject* camera_get_raw(PyCameraObject* self);
+
+/*
+ * Functions available to pygame users.  The idea is to make these as simple as
+ * possible, and merely have them call functions specific to the type of 
+ * camera being used to do all the real work.  It currently just calls v4l2_*
+ * functions, but it could check something like self->cameratype and depending
+ * on the result, call v4l, v4l2, vfw, or other functions.
+ */
+
+/* colorspace() - Surface colorspace conversion */
+PyObject* surf_colorspace (PyObject* self, PyObject* arg)
+{
+    PyObject *surfobj, *surfobj2;
+    SDL_Surface* surf, *newsurf;
+    char* color;
+    int cspace;
+    surfobj2 = NULL;
+
+    /*get all the arguments*/
+    if (!PyArg_ParseTuple (arg, "O!s|O!", &PySurface_Type, &surfobj, 
+                           &color, &PySurface_Type, &surfobj2))
+        return NULL;
+
+    if (!strcmp(color, "YUV")) {
+        cspace = YUV_OUT;
+    } else if (!strcmp(color, "HSV")) {
+        cspace = HSV_OUT;
+    } else {
+        return RAISE (PyExc_ValueError, "Incorrect colorspace value");
+    }
+
+    surf = PySurface_AsSurface (surfobj);
+	
+    if (!surfobj2) {
+        newsurf = SDL_CreateRGBSurface (0, surf->w, surf->h,
+            surf->format->BitsPerPixel, surf->format->Rmask,
+            surf->format->Gmask, surf->format->Bmask, surf->format->Amask);
+        if (!newsurf) {
+            return NULL;
+        }
+    } else {
+        newsurf = PySurface_AsSurface (surfobj2);
+    }
+
+    /* check to see if the size is the same. */
+    if (newsurf->w != surf->w || newsurf->h != surf->h)
+        return RAISE (PyExc_ValueError, 
+                      "Surfaces not the same width and height.");
+
+    /* check to see if the format of the surface is the same. */
+    if (surf->format->BitsPerPixel != newsurf->format->BitsPerPixel)
+        return RAISE (PyExc_ValueError, "Surfaces not the same depth");
+
+    SDL_LockSurface (newsurf);
+    PySurface_Lock (surfobj);
+
+    Py_BEGIN_ALLOW_THREADS;
+    colorspace (surf, newsurf, cspace);
+    Py_END_ALLOW_THREADS;
+
+    PySurface_Unlock (surfobj);
+    SDL_UnlockSurface (newsurf);
+
+    if (surfobj2)
+    {
+        Py_INCREF (surfobj2);
+        return surfobj2;
+    }
+    else
+        return PySurface_New (newsurf);
+}
+
+/* list_cameras() - lists cameras available on the computer */
+PyObject* list_cameras (PyObject* self, PyObject* arg)
+{
+#if defined(__unix__)
+    PyObject* ret_list;
+    PyObject* string;
+    char** devices;
+    int num_devices, i;
+    
+    num_devices = 0;
+    ret_list = NULL;
+    ret_list = PyList_New (0);
+    if (!ret_list)
+        return NULL;
+
+    devices = v4l2_list_cameras(&num_devices);
+    
+    for(i = 0; i < num_devices; i++) {
+        string = PyString_FromString(devices[i]);
+        PyList_Append(ret_list, string);
+        Py_DECREF(string);
+        free(devices[i]);
+    }
+    free(devices);
+    
+    return ret_list;
+#else
+	Py_RETURN_NONE;
+#endif
+}
+
+/* start() - opens, inits, and starts capturing on the camera */
+PyObject* camera_start (PyCameraObject* self)
+{
+#if defined(__unix__)
+    if (v4l2_open_device(self) == 0) {
+        if (v4l_open_device(self) == 0) {
+            v4l2_close_device(self);
+            return NULL;
+        } else {
+            self->camera_type = CAM_V4L;
+            if (v4l_init_device(self) == 0) {
+                v4l2_close_device(self);
+                return NULL;
+            }
+            if (v4l_start_capturing(self) == 0) {
+                v4l2_close_device(self);
+                return NULL;
+            }
+        }
+    } else {
+        self->camera_type = CAM_V4L2;
+        if (v4l2_init_device(self) == 0) {
+            v4l2_close_device(self);
+            return NULL;
+        }
+        if (v4l2_start_capturing(self) == 0) {
+            v4l2_close_device(self);
+            return NULL;
+        }
+    }
+#endif
+    Py_RETURN_NONE;
+}
+
+/* stop() - stops capturing, uninits, and closes the camera */
+PyObject* camera_stop (PyCameraObject* self)
+{
+#if defined(__unix__)
+    if (v4l2_stop_capturing(self) == 0)
+        return NULL;
+    if (v4l2_uninit_device(self) == 0)
+        return NULL;
+    if (v4l2_close_device(self) == 0)
+        return NULL;
+#endif
+    Py_RETURN_NONE;
+}
+
+/* get_controls() - gets current values of user controls */
+/* TODO: Support brightness, contrast, and other common controls */
+PyObject* camera_get_controls (PyCameraObject* self)
+{
+    int value;
+#if defined(__unix__)    
+    if (v4l2_get_control(self->fd, V4L2_CID_HFLIP, &value))
+        self->hflip = value;
+    
+    if (v4l2_get_control(self->fd, V4L2_CID_VFLIP, &value))
+        self->vflip = value;
+
+    if (v4l2_get_control(self->fd, V4L2_CID_BRIGHTNESS, &value))
+        self->brightness = value;
+#endif    
+    return Py_BuildValue ("(NNN)", PyBool_FromLong(self->hflip), PyBool_FromLong(self->vflip), PyInt_FromLong(self->brightness));
+}
+
+/* set_controls() - changes camera settings if supported by the camera */
+PyObject* camera_set_controls (PyCameraObject* self, PyObject* arg, PyObject *kwds)
+{
+    int hflip = 0, vflip = 0, brightness = 0;
+    char *kwids[] = {"hflip", "vflip", "brightness", NULL};
+
+    camera_get_controls(self);
+    hflip = self->hflip;
+    vflip = self->vflip;
+    brightness = self->brightness;
+    
+    if (!PyArg_ParseTupleAndKeywords(arg, kwds, "|iii", kwids, &hflip, &vflip, &brightness))
+        return NULL;
+#if defined(__unix__)        
+    if (v4l2_set_control(self->fd, V4L2_CID_HFLIP, hflip))
+        self->hflip = hflip;
+        
+    if (v4l2_set_control(self->fd, V4L2_CID_VFLIP, vflip))
+        self->vflip = vflip;
+        
+    if (v4l2_set_control(self->fd, V4L2_CID_BRIGHTNESS, brightness))
+        self->brightness = brightness;
+#endif    
+    return Py_BuildValue ("(NNN)", PyBool_FromLong(self->hflip), PyBool_FromLong(self->vflip), PyInt_FromLong(self->brightness));
+}
+
+/* get_size() - returns the dimensions of the images being recorded */
+PyObject* camera_get_size (PyCameraObject* self)
+{
+    return Py_BuildValue ("(ii)", self->width, self->height);
+}
+
+/* query_image() - checks if a frame is ready */
+PyObject* camera_query_image (PyCameraObject* self)
+{
+#if defined(__unix__)
+    return PyBool_FromLong(v4l2_query_buffer(self));
+#endif
+    Py_RETURN_NONE;
+}
+
+/* get_image() - returns an RGB Surface */
+/* code to reuse Surface from René Dudfield */
+PyObject* camera_get_image (PyCameraObject* self, PyObject* arg)
+{
+    SDL_Surface* surf = NULL;
+    PyObject *surfobj = NULL;
+    
+    if (!PyArg_ParseTuple (arg, "|O!", &PySurface_Type, &surfobj))
+        return NULL;
+
+    if (!surfobj) {
+        surf = SDL_CreateRGBSurface (0, self->width, self->height, 24, 0xFF<<16, 
+                                 0xFF<<8, 0xFF, 0);
+    } else {
+        surf = PySurface_AsSurface (surfobj);
+    }
+    
+    if (!surf)
+        return NULL;
+        
+    if (surf->w != self->width || surf->h != self->height) {
+        return RAISE (PyExc_ValueError, 
+                      "Destination surface not the correct width or height.");
+    }
+#if defined(__unix__)
+    Py_BEGIN_ALLOW_THREADS;
+    if (!v4l2_read_frame(self, surf))
+        return NULL;
+    Py_END_ALLOW_THREADS;
+#endif
+    if (!surf)
+        return NULL;
+        
+    if (surfobj) {
+        Py_INCREF (surfobj);
+        return surfobj;
+    } else {
+        return PySurface_New (surf);
+    }
+}
+
+/* get_raw() - returns an unmodified image as a string from the buffer */
+PyObject* camera_get_raw(PyCameraObject* self)
+{
+#if defined(__unix__)
+    return v4l2_read_raw(self);
+#endif
+    Py_RETURN_NONE;
+}
+
+/*
+ * Pixelformat conversion functions
+ */
+ 
+/* converts from rgb Surface to yuv or hsv */
+/* TODO: Allow for conversion from yuv and hsv to all */
+void colorspace (SDL_Surface *src, SDL_Surface *dst, int cspace)
+{   
+    switch (cspace) {
+        case YUV_OUT:
+            rgb_to_yuv (src->pixels, dst->pixels, src->h * src->w, 0, src->format);
+            break;
+        case HSV_OUT:
+            rgb_to_hsv (src->pixels, dst->pixels, src->h * src->w, 0, src->format);
+            break;
+    }
+}
+
+/* converts pretty directly if its already RGB24 */
+void rgb24_to_rgb (const void* src, void* dst, int length, SDL_PixelFormat* format)
+{
+    Uint8 *s = (Uint8 *) src;
+    Uint8 *d8;
+    Uint16 *d16;
+    Uint32 *d32;
+    Uint8 r, g, b;
+    int rshift, gshift, bshift, rloss, gloss, bloss;
+
+    rshift = format->Rshift;
+    gshift = format->Gshift;
+    bshift = format->Bshift;
+    rloss = format->Rloss;
+    gloss = format->Gloss;
+    bloss = format->Bloss;
+
+    switch (format->BytesPerPixel) {
+        case 1:
+            d8 = (Uint8 *) dst;
+            while (length--) {
+                r = *s++;
+                g = *s++;
+                b = *s++;
+                *d8++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
+            }
+            break;
+        case 2:
+            d16 = (Uint16 *) dst;
+            while (length--) {
+                r = *s++;
+                g = *s++;
+                b = *s++;
+                *d16++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
+            }
+            break;
+        case 3:
+            d8 = (Uint8 *) dst;
+            while (length--) {
+                *d8++ = *(s+2); /* blue */
+                *d8++ = *(s+1); /* green */
+                *d8++ = *s; /* red */
+                s += 3;
+            }
+            break;
+        default:
+            d32 = (Uint32 *) dst;
+            while (length--) {
+                r = *s++;
+                g = *s++;
+                b = *s++;
+                *d32++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
+            }
+            break;
+    }
+}
+
+/* converts packed rgb to packed hsv. formulas modified from wikipedia */
+void rgb_to_hsv (const void* src, void* dst, int length, 
+                 unsigned long source, SDL_PixelFormat* format)
+{
+    Uint8 *s8, *d8;
+    Uint16 *s16, *d16;
+    Uint32 *s32, *d32;
+    Uint8 r, g, b, p1, p2, h, s, v, max, min, delta;
+    int rshift, gshift, bshift, rloss, gloss, bloss;
+
+    s8 = (Uint8 *) src;
+    s16 = (Uint16 *) src;
+    s32 = (Uint32 *) src;
+    d8 = (Uint8 *) dst;
+    d16 = (Uint16 *) dst;
+    d32 = (Uint32 *) dst;
+    rshift = format->Rshift;
+    gshift = format->Gshift;
+    bshift = format->Bshift;
+    rloss = format->Rloss;
+    gloss = format->Gloss;
+    bloss = format->Bloss;
+    
+    /* you could stick the if statement inside the loop, but I'm sacrificing a
+       a few hundred bytes for a little performance */
+    if (source == V4L2_PIX_FMT_RGB444) {
+        while (length--) {
+            p1 = *s8++;
+            p2 = *s8++;
+            b = p2 << 4;
+            g = p1 & 0xF0;
+            r = p1 << 4;
+            max = MAX(MAX(r, g), b);
+            min = MIN(MIN(r, g), b);
+            delta = max - min;
+            v = max; /* value (similar to luminosity) */
+            if (!delta) { /* grey, zero hue and saturation */
+                s = 0;
+                h = 0;
+            } else {
+                s = 255*delta/max; /* saturation */
+                if (r == max) {  /* set hue based on max color */
+                    h = 43*(g - b)/delta;
+                } else if (g == max) {
+                    h = 85 + 43*(b - r)/delta;
+                } else {
+                    h = 170 + 43*(r - g)/delta;
+                }
+            }
+            switch (format->BytesPerPixel) {
+                case 1:
+                   *d8++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+                case 2:
+                   *d16++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+                case 3:
+                   *d8++ = v;
+                   *d8++ = s;
+                   *d8++ = h;
+                   break;
+                default:
+                   *d32++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+            }
+        }
+    } else if (source == V4L2_PIX_FMT_RGB24) {
+        while (length--) {
+            r = *s8++;
+            g = *s8++;
+            b = *s8++;
+            max = MAX(MAX(r, g), b);
+            min = MIN(MIN(r, g), b);
+            delta = max - min;
+            v = max; /* value (similar to luminosity) */
+            if (!delta) { /* grey, zero hue and saturation */
+                s = 0;
+                h = 0;
+            } else {
+                s = 255*delta/max; /* saturation */
+                if (r == max) {  /* set hue based on max color */
+                    h = 43*(g - b)/delta;
+                } else if (g == max) {
+                    h = 85 + 43*(b - r)/delta;
+                } else {
+                    h = 170 + 43*(r - g)/delta;
+                }
+            }
+            switch (format->BytesPerPixel) {
+                case 1:
+                   *d8++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+                case 2:
+                   *d16++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+                case 3:
+                   *d8++ = v;
+                   *d8++ = s;
+                   *d8++ = h;
+                   break;
+                default:
+                   *d32++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+            }
+        }
+    } else { /* for use as stage 2 in yuv or bayer to hsv, r and b switched */
+        while (length--) {
+            switch (format->BytesPerPixel) {
+                case 1:
+                   r = *s8 >> rshift << rloss;
+                   g = *s8 >> gshift << gloss;
+                   b = *s8++ >> bshift << bloss;
+                   break;
+                case 2:
+                   r = *s16 >> rshift << rloss;
+                   g = *s16 >> gshift << gloss;
+                   b = *s16++ >> bshift << bloss;
+                   break;
+                case 3:
+                   b = *s8++;
+                   g = *s8++;
+                   r = *s8++;
+                   break;
+                default:
+                   r = *s32 >> rshift << rloss;
+                   g = *s32 >> gshift << gloss;
+                   b = *s32++ >> bshift << bloss;
+                   break;
+            }
+            max = MAX(MAX(r, g), b);
+            min = MIN(MIN(r, g), b);
+            delta = max - min;
+            v = max; /* value (similar to luminosity) */
+            if (!delta) { /* grey, zero hue and saturation */
+                s = 0;
+                h = 0;
+            } else {
+                s = 255*delta/max; /* saturation */
+                if (r == max) {  /* set hue based on max color */
+                    h = 43*(g - b)/delta;
+                } else if (g == max) {
+                    h = 85 + 43*(b - r)/delta;
+                } else {
+                    h = 170 + 43*(r - g)/delta;
+                }
+            }
+            switch (format->BytesPerPixel) {
+                case 1:
+                   *d8++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+                case 2:
+                   *d16++ = ((h >> rloss) << rshift) + ((s >> gloss) << gshift) + ((v >> bloss) << bshift);
+                   break;
+                case 3:
+                   *d8++ = v;
+                   *d8++ = s;
+                   *d8++ = h;
+                   break;
+                default:
+                   *d32++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+            }
+        }
+    }
+}
+
+/* convert packed rgb to yuv. Note that unlike many implementations of YUV,
+   this has a full range of 0-255 for Y, not 16-235. Formulas from wikipedia */
+void rgb_to_yuv (const void* src, void* dst, int length, 
+                 unsigned long source, SDL_PixelFormat* format)
+{
+    Uint8 *s8, *d8;
+    Uint16 *s16, *d16;
+    Uint32 *s32, *d32;
+    Uint8 r, g, b, y, u, v;
+    Uint8 p1, p2;
+    int rshift, gshift, bshift, rloss, gloss, bloss;
+
+    s8 = (Uint8 *) src;
+    s16 = (Uint16 *) src;
+    s32 = (Uint32 *) src;
+    d8 = (Uint8 *) dst;
+    d16 = (Uint16 *) dst;
+    d32 = (Uint32 *) dst;
+    rshift = format->Rshift;
+    gshift = format->Gshift;
+    bshift = format->Bshift;
+    rloss = format->Rloss;
+    gloss = format->Gloss;
+    bloss = format->Bloss;
+    
+    if (source == V4L2_PIX_FMT_RGB444) {    
+        while (length--) {
+            p1 = *s8++;
+            p2 = *s8++;
+            b = p2 << 4;
+            g = p1 & 0xF0;
+            r = p1 << 4;
+            v = ((112*r-94*g-18*b + 128) >> 8) + 128;  /* V */
+            u = ((-38*r-74*g+112*b + 128) >> 8) + 128; /* U */
+            y = (77*r+150*g+29*b + 128) >> 8; /* Y */
+            switch (format->BytesPerPixel) {
+                case 1:
+                   *d8++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+                case 2:
+                   *d16++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+                case 3:
+                   *d8++ = v;
+                   *d8++ = u;
+                   *d8++ = y;
+                   break;
+                default:
+                   *d32++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+            }
+        }
+    } else if (source == V4L2_PIX_FMT_RGB24) {
+        while (length--) {
+            r = *s8++;
+            g = *s8++;
+            b = *s8++;
+            v = ((112*r-94*g-18*b + 128) >> 8) + 128;  /* V */
+            u = ((-38*r-74*g+112*b + 128) >> 8) + 128; /* U */
+            y = (77*r+150*g+29*b + 128) >> 8; /* Y */
+            switch (format->BytesPerPixel) {
+                case 1:
+                   *d8++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+                case 2:
+                   *d16++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+                case 3:
+                   *d8++ = v;
+                   *d8++ = u;
+                   *d8++ = y;
+                   break;
+                default:
+                   *d32++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+                   break;
+            }
+        }
+    } else { /* for use as stage 2 in bayer to yuv, r and b switched */
+        switch (format->BytesPerPixel) {
+            case 1:
+                while (length--) {
+                    r = *s8 >> rshift << rloss;
+                    g = *s8 >> gshift << gloss;
+                    b = *s8++ >> bshift << bloss;
+                    *d8++ = ((((77*r+150*g+29*b + 128) >> 8) >> rloss) << rshift) | (((((-38*r-74*g+112*b + 128) >> 8) + 128) >> gloss) << gshift) | (((((112*r-94*g-18*b + 128) >> 8) + 128) >> bloss) << bshift);
+                }
+                break;
+            case 2:
+                while (length--) {
+                    r = *s16 >> rshift << rloss;
+                    g = *s16 >> gshift << gloss;
+                    b = *s16++ >> bshift << bloss;
+                    *d16++ = ((((77*r+150*g+29*b + 128) >> 8) >> rloss) << rshift) | (((((-38*r-74*g+112*b + 128) >> 8) + 128) >> gloss) << gshift) | (((((112*r-94*g-18*b + 128) >> 8) + 128) >> bloss) << bshift);
+                }
+                break;
+            case 3:
+                while (length--) {
+                    b = *s8++;
+                    g = *s8++;
+                    r = *s8++;
+                    *d8++ = ((112*r-94*g-18*b + 128) >> 8) + 128;
+                    *d8++ = ((-38*r-74*g+112*b + 128) >> 8) + 128;
+                    *d8++ = (77*r+150*g+29*b + 128) >> 8;
+                }
+                break;
+            default:
+                while (length--) {
+                    r = *s32 >> rshift << rloss;
+                    g = *s32 >> gshift << gloss;
+                    b = *s32++ >> bshift << bloss;
+                    *d32++ = ((((77*r+150*g+29*b + 128) >> 8) >> rloss) << rshift) | (((((-38*r-74*g+112*b + 128) >> 8) + 128) >> gloss) << gshift) | (((((112*r-94*g-18*b + 128) >> 8) + 128) >> bloss) << bshift);
+                }
+                break;
+        }
+    }
+}
+
+/* Converts from rgb444 (R444) to rgb24 (RGB3) */
+void rgb444_to_rgb (const void* src, void* dst, int length, SDL_PixelFormat* format)
+{
+    Uint8 *s, *d8;
+    Uint16 *d16;
+    Uint32 *d32;
+    Uint8 p1, p2, r, g, b;
+    int rshift, gshift, bshift, rloss, gloss, bloss;
+    
+    s = (Uint8 *) src;
+    rshift = format->Rshift;
+    gshift = format->Gshift;
+    bshift = format->Bshift;
+    rloss = format->Rloss;
+    gloss = format->Gloss;
+    bloss = format->Bloss;
+    
+    switch (format->BytesPerPixel) {
+        case 1:
+            d8 = (Uint8 *) dst;
+            while (length--) {
+               r = *s << 4;
+               g = *s++ & 0xF0;
+               b = *s++ << 4;
+               *d8++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
+            }
+            break;
+        case 2:
+            d16 = (Uint16 *) dst;
+            while (length--) {
+               r = *s << 4;
+               g = *s++ & 0xF0;
+               b = *s++ << 4;
+               *d16++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
+            }
+            break;
+        case 3:
+            d8 = (Uint8 *) dst;    
+            while (length--) {
+                p1 = *s++;
+                p2 = *s++;
+                *d8++ = p2 << 4; /* blue */
+                *d8++ = p1 & 0xF0; /* green */
+                *d8++ = p1 << 4; /* red */
+            }
+            break;
+        default:
+            d32 = (Uint32 *) dst;
+            while (length--) {
+               r = *s << 4;
+               g = *s++ & 0xF0;
+               b = *s++ << 4;
+               *d32++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
+            }
+            break;
+    }
+}   
+
+/* convert from 4:2:2 YUYV interlaced to RGB24 */
+/* modified from OpenCV, based on ccvt_yuyv_bgr32() from camstream */
+void yuyv_to_rgb (const void* src, void* dst, int length, SDL_PixelFormat* format)
+{
+    Uint8 *s, *d8;
+    Uint16 *d16;
+    Uint32 *d32;
+    int i, cb, cg, cr;
+    Uint8 r1, g1, b1, r2, b2, g2, y1, y2;
+    int rshift, gshift, bshift, rloss, gloss, bloss;
+
+    rshift = format->Rshift;
+    gshift = format->Gshift;
+    bshift = format->Bshift;
+    rloss = format->Rloss;
+    gloss = format->Gloss;
+    bloss = format->Bloss;
+    
+    d8 = (Uint8 *) dst;
+    d16 = (Uint16 *) dst;
+    d32 = (Uint32 *) dst;
+    i = length >> 1;
+    s = (Uint8 *) src;
+
+    while (i--) {
+        y1 = *s++;
+        cb = ((*s - 128) * 454) >> 8;
+        cg = (*s++ - 128) * 88;
+        y2 = *s++;
+        cr = ((*s - 128) * 359) >> 8;
+        cg = (cg + (*s++ - 128) * 183) >> 8;
+
+        r1 = SAT2(y1 + cr);
+        b1 = SAT2(y1 + cb);
+        g1 = SAT2(y1 - cg);
+
+        r2 = SAT2(y2 + cr);
+        b2 = SAT2(y2 + cb);
+        g2 = SAT2(y2 - cg);
+        switch (format->BytesPerPixel) {
+            case 1:
+               *d8++ = ((r1 >> rloss) << rshift) | ((g1 >> gloss) << gshift) | ((b1 >> bloss) << bshift);
+               *d8++ = ((r2 >> rloss) << rshift) | ((g2 >> gloss) << gshift) | ((b2 >> bloss) << bshift);
+               break;
+            case 2:
+               *d16++ = ((r1 >> rloss) << rshift) | ((g1 >> gloss) << gshift) | ((b1 >> bloss) << bshift);
+               *d16++ = ((r2 >> rloss) << rshift) | ((g2 >> gloss) << gshift) | ((b2 >> bloss) << bshift);
+               break;
+            case 3:
+               *d8++ = b1;
+               *d8++ = g1;
+               *d8++ = r1;
+               *d8++ = b2;
+               *d8++ = g2;
+               *d8++ = r2;
+               break;
+            default:
+               *d32++ = ((r1 >> rloss) << rshift) | ((g1 >> gloss) << gshift) | ((b1 >> bloss) << bshift);
+               *d32++ = ((r2 >> rloss) << rshift) | ((g2 >> gloss) << gshift) | ((b2 >> bloss) << bshift);
+               break;
+        }
+    }
+}
+
+/* turn yuyv into packed yuv. */
+void yuyv_to_yuv (const void* src, void* dst, int length, SDL_PixelFormat* format)
+{
+    Uint8 *s, *d8;
+    Uint8 y1, u, y2, v;
+    Uint16 *d16;
+    Uint32 *d32;
+    int i = length >> 1;
+    int rshift, gshift, bshift, rloss, gloss, bloss;
+    
+    rshift = format->Rshift;
+    gshift = format->Gshift;
+    bshift = format->Bshift;
+    rloss = format->Rloss;
+    gloss = format->Gloss;
+    bloss = format->Bloss;
+    s = (Uint8 *) src;
+
+    switch (format->BytesPerPixel) {
+        case 1:
+            d8 = (Uint8 *) dst;
+            while (i--) {
+                y1 = *s++;
+                u = *s++;
+                y2 = *s++;
+                v = *s++;
+                *d8++ = ((y1 >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+                *d8++ = ((y2 >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+            }
+            break;
+        case 2:
+            d16 = (Uint16 *) dst;
+            while (i--) {
+                y1 = *s++;
+                u = *s++;
+                y2 = *s++;
+                v = *s++;
+                *d16++ = ((y1 >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+                *d16++ = ((y2 >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+            }
+            break;
+        case 3:
+            d8 = (Uint8 *) dst;
+            while (i--) {
+                *d8++ = *(s+3); /* v */
+                *d8++ = *(s+1); /* u */
+                *d8++ = *s; /* y1 */
+                *d8++ = *(s+3); /* v */
+                *d8++ = *(s+1); /* u */
+                *d8++ = *(s+2); /* y2 */
+                s += 4;
+            }
+            break;
+        default:
+            d32 = (Uint32 *) dst;
+            while (i--) {
+                y1 = *s++;
+                u = *s++;
+                y2 = *s++;
+                v = *s++;
+                *d32++ = ((y1 >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+                *d32++ = ((y2 >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
+            }
+            break;
+    }
+}
+
+/* Converts from 8 bit Bayer (BA81) to rgb24 (RGB3) */
+/* from Sonix SN9C10x routines by Takafumi Mizuno <taka-qce@ls-a.jp> */
+/* FIXME: Seems to be grayscale and kind of dark on the OLPC XO */
+/*        Maybe the result of a different Bayer color order on the screen? */
+/* TODO: Certainly not the most efficient way of doing this conversion. */
+void sbggr8_to_rgb (const void* src, void* dst, int width, int height, SDL_PixelFormat* format)
+{
+    Uint8 *rawpt, *d8;
+    Uint16 *d16;
+    Uint32 *d32;
+    Uint8 r, g, b;
+    int rshift, gshift, bshift, rloss, gloss, bloss;
+    int i = width * height;
+    rawpt = (Uint8*) src;
+    rshift = format->Rshift;
+    gshift = format->Gshift;
+    bshift = format->Bshift;
+    rloss = format->Rloss;
+    gloss = format->Gloss;
+    bloss = format->Bloss;
+    
+    d8 = (Uint8 *) dst;
+    d16 = (Uint16 *) dst;
+    d32 = (Uint32 *) dst;
+        
+    while (i--) {
+        if ( (i/width) % 2 == 0 ) {
+            /* even row (BGBGBGBG)*/
+            if ( (i % 2) == 0 ) {
+                /* B */
+                if ( (i > width) && ((i % width) > 0) ) {
+                    b = *rawpt;                    /* B */
+                    g = (*(rawpt-1)+*(rawpt+1)+
+                    *(rawpt+width)+*(rawpt-width))/4;      /* G */
+                    r = (*(rawpt-width-1)+*(rawpt-width+1)+
+                    *(rawpt+width-1)+*(rawpt+width+1))/4;  /* R */
+                } else {
+                    /* first line or left column */
+                    b = *rawpt;                             /* B */
+                    g = (*(rawpt+1)+*(rawpt+width))/2;      /* G */
+                    r = *(rawpt+width+1);                   /* R */
+                }
+            } else {
+                /* (B)G */
+                if ( (i > width) && ((i % width) < (width-1)) ) {
+                    b = (*(rawpt-1)+*(rawpt+1))/2;          /* B */
+                    g = *rawpt;                             /* G */
+                    r = (*(rawpt+width)+*(rawpt-width))/2;  /* R */
+                } else {
+                    /* first line or right column */
+                    b = *(rawpt-1);         /* B */
+                    g = *rawpt;             /* G */
+                    r = *(rawpt+width);     /* R */
+                }
+            }
+        } else {
+            /* odd row (GRGRGRGR) */
+            if ( (i % 2) == 0 ) {
+                /* G(R) */
+                if ( (i < (width*(height-1))) && ((i % width) > 0) ) {
+                    b = (*(rawpt+width)+*(rawpt-width))/2;  /* B */
+                    g = *rawpt;                             /* G */
+                    r = (*(rawpt-1)+*(rawpt+1))/2;          /* R */
+                } else {
+                    /* bottom line or left column */
+                    b = *(rawpt-width);     /* B */
+                    g = *rawpt;             /* G */
+                    r = *(rawpt+1);         /* R */
+                }
+            } else {
+                /* R */
+                if ( i < (width*(height-1)) && ((i % width) < (width-1)) ) {
+                    b = (*(rawpt-width-1)+*(rawpt-width+1)+                    
+                    *(rawpt+width-1)+*(rawpt+width+1))/4;  /* B */
+                    g = (*(rawpt-1)+*(rawpt+1)+
+                    *(rawpt-width)+*(rawpt+width))/4;      /* G */
+                    r = *rawpt;                    /* R */
+                } else {
+                    /* bottom line or right column */
+                    b = *(rawpt-width-1);                   /* B */
+                    g = (*(rawpt-1)+*(rawpt-width))/2;      /* G */
+                    r = *rawpt;                             /* R */
+                }
+            }
+        }
+        rawpt++;
+        switch (format->BytesPerPixel) {
+            case 1:
+               *d8++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
+               break;
+            case 2:
+               *d16++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
+               break;
+            case 3:
+               *d8++ = b;
+               *d8++ = g;
+               *d8++ = r;
+               break;
+            default:
+               *d32++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
+               break;
+        }
+    }
+}
+
+
+/* convert from YUV 4:2:0 (YU12) to RGB24 */
+/* modified from ccvt_c2.c from camstream by Tony Hague */
+void yuv420_to_rgb (const void* src, void* dst, int width, int height, SDL_PixelFormat* format)
+{
+    const Uint8 *y1, *y2, *u, *v;
+    Uint8 yp;
+    Uint8 *d8_1, *d8_2;
+    Uint16 *d16_1, *d16_2;
+    Uint32 *d32_1, *d32_2;
+    int rshift, gshift, bshift, rloss, gloss, bloss, j, i, cr, cb, cg;
+
+    rshift = format->Rshift;
+    gshift = format->Gshift;
+    bshift = format->Bshift;
+    rloss = format->Rloss;
+    gloss = format->Gloss;
+    bloss = format->Bloss;
+    
+    d8_1 = (Uint8 *) dst;
+    d8_2 = d8_1 + (format->BytesPerPixel == 3 ? width*3 : 3);
+    d16_1 = (Uint16 *) dst;
+    d16_2 = d16_1 + width;
+    d32_1 = (Uint32 *) dst;
+    d32_2 = d32_1 + width;
+    y1 = (Uint8 *) src;
+    y2 = y1 + width;
+    u = y1 + width * height;
+    v = u + (width * height) / 4;    
+    j = height / 2;
+
+    switch (format->BytesPerPixel) {
+        case 1:
+            while (j--) {
+                i = width/2;
+                while (i--) {
+                    cb = ((*u-128) * 454)>>8;
+                    cr = ((*v-128) * 359)>>8;
+                    cg = ((*v++-128) * 183 + (*u++-128) * 88)>>8;
+                    yp = *y1++;
+                    *d8_1++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp - cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                    yp = *y1++;
+                    *d8_1++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp + cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                    yp = *y2++;
+                    *d8_2++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp + cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                    yp = *y2++;
+                    *d8_2++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp + cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                }
+                y1 = y2;
+                y2 += width;
+                d8_1 = d8_2;
+                d8_2 += width;
+            }
+            break;
+        case 2:
+            while (j--) {
+                i = width/2;
+                while (i--) {
+                    cb = ((*u-128) * 454)>>8;
+                    cr = ((*v-128) * 359)>>8;
+                    cg = ((*v++-128) * 183 + (*u++-128) * 88)>>8;
+                    yp = *y1++;
+                    *d16_1++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp - cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                    yp = *y1++;
+                    *d16_1++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp + cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                    yp = *y2++;
+                    *d16_2++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp + cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                    yp = *y2++;
+                    *d16_2++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp + cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                }
+                y1 = y2;
+                y2 += width;
+                d16_1 = d16_2;
+                d16_2 += width;
+            }
+            break;
+        case 3:
+            while (j--) {
+                i = width/2;
+                while (i--) {
+                    cb = ((*u-128) * 454)>>8;
+                    cr = ((*v-128) * 359)>>8;
+                    cg = ((*v++-128) * 183 + (*u++-128) * 88)>>8;
+                    yp = *y1++;
+                    *d8_1++ = SAT2(yp + cb);
+                    *d8_1++ = SAT2(yp - cg);
+                    *d8_1++ = SAT2(yp + cr);
+                    yp = *y1++;
+                    *d8_1++ = SAT2(yp + cb);
+                    *d8_1++ = SAT2(yp - cg);
+                    *d8_1++ = SAT2(yp + cr);
+                    yp = *y2++;
+                    *d8_2++ = SAT2(yp + cb);
+                    *d8_2++ = SAT2(yp - cg);
+                    *d8_2++ = SAT2(yp + cr);
+                    yp = *y2++;
+                    *d8_2++ = SAT2(yp + cb);
+                    *d8_2++ = SAT2(yp - cg);
+                    *d8_2++ = SAT2(yp + cr);
+                }
+                y1 = y2;
+                y2 += width;
+                d8_1 = d8_2;
+                d8_2 += width*3;
+            }
+            break;
+        default:
+            while (j--) {
+                i = width/2;
+                while (i--) {
+                    cb = ((*u-128) * 454)>>8;
+                    cr = ((*v-128) * 359)>>8;
+                    cg = ((*v++-128) * 183 + (*u++-128) * 88)>>8;
+                    yp = *y1++;
+                    *d32_1++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp - cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                    yp = *y1++;
+                    *d32_1++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp + cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                    yp = *y2++;
+                    *d32_2++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp + cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                    yp = *y2++;
+                    *d32_2++ = ((SAT2(yp + cr) >> rloss) << rshift) | ((SAT2(yp + cg) >> gloss) << gshift) | ((SAT2(yp + cb) >> bloss) << bshift);
+                }
+                y1 = y2;
+                y2 += width;
+                d32_1 = d32_2;
+                d32_2 += width;
+            }
+            break;
+    }
+}
+
+/* turn yuv420 into packed yuv. */
+void yuv420_to_yuv (const void* src, void* dst, int width, int height, SDL_PixelFormat* format)
+{
+    const Uint8 *y1, *y2, *u, *v;
+    Uint8 *d8_1, *d8_2;
+    Uint16 *d16_1, *d16_2;
+    Uint32 *d32_1, *d32_2;
+    int rshift, gshift, bshift, rloss, gloss, bloss, j, i;
+
+    rshift = format->Rshift;
+    gshift = format->Gshift;
+    bshift = format->Bshift;
+    rloss = format->Rloss;
+    gloss = format->Gloss;
+    bloss = format->Bloss;
+    
+    d8_1 = (Uint8 *) dst;
+    d8_2 = d8_1 + (format->BytesPerPixel == 3 ? width*3 : 3);
+    d16_1 = (Uint16 *) dst;
+    d16_2 = d16_1 + width;
+    d32_1 = (Uint32 *) dst;
+    d32_2 = d32_1 + width;
+    y1 = (Uint8 *) src;
+    y2 = y1 + width;
+    u = y1 + width * height;
+    v = u + (width * height) / 4;    
+    j = height / 2;
+
+    switch (format->BytesPerPixel) {
+        case 1:
+            while (j--) {
+                i = width/2;
+                while (i--) {
+                    *d8_1++ = ((*y1++ >> rloss) << rshift) | ((*u >> gloss) << gshift) | ((*v >> bloss) << bshift);
+                    *d8_1++ = ((*y1++ >> rloss) << rshift) | ((*u >> gloss) << gshift) | ((*v >> bloss) << bshift);
+                    *d8_2++ = ((*y2++ >> rloss) << rshift) | ((*u >> gloss) << gshift) | ((*v >> bloss) << bshift);
+                    *d8_2++ = ((*y2++ >> rloss) << rshift) | ((*u++ >> gloss) << gshift) | ((*v++ >> bloss) << bshift);
+                }
+                y1 = y2;
+                y2 += width;
+                d8_1 = d8_2;
+                d8_2 += width;
+            }
+            break;
+        case 2:
+            while (j--) {
+                i = width/2;
+                while (i--) {
+                    *d16_1++ = ((*y1++ >> rloss) << rshift) | ((*u >> gloss) << gshift) | ((*v >> bloss) << bshift);
+                    *d16_1++ = ((*y1++ >> rloss) << rshift) | ((*u >> gloss) << gshift) | ((*v >> bloss) << bshift);
+                    *d16_2++ = ((*y2++ >> rloss) << rshift) | ((*u >> gloss) << gshift) | ((*v >> bloss) << bshift);
+                    *d16_2++ = ((*y2++ >> rloss) << rshift) | ((*u++ >> gloss) << gshift) | ((*v++ >> bloss) << bshift);
+                }
+                y1 = y2;
+                y2 += width;
+                d16_1 = d16_2;
+                d16_2 += width;
+            }
+            break;
+        case 3:
+            while (j--) {
+                i = width/2;
+                while (i--) {
+                    *d8_1++ = *v;
+                    *d8_1++ = *u;
+                    *d8_1++ = *y1++;
+                    *d8_1++ = *v;
+                    *d8_1++ = *u;
+                    *d8_1++ = *y1++;
+                    *d8_2++ = *v;
+                    *d8_2++ = *u;
+                    *d8_2++ = *y2++;
+                    *d8_2++ = *v++;
+                    *d8_2++ = *u++;
+                    *d8_2++ = *y2++;
+                }
+                y1 = y2;
+                y2 += width;
+                d8_1 = d8_2;
+                d8_2 += width*3;
+            }
+            break;
+        default:
+            while (j--) {
+                i = width/2;
+                while (i--) {
+                    *d32_1++ = ((*y1++ >> rloss) << rshift) | ((*u >> gloss) << gshift) | ((*v >> bloss) << bshift);
+                    *d32_1++ = ((*y1++ >> rloss) << rshift) | ((*u >> gloss) << gshift) | ((*v >> bloss) << bshift);
+                    *d32_2++ = ((*y2++ >> rloss) << rshift) | ((*u >> gloss) << gshift) | ((*v >> bloss) << bshift);
+                    *d32_2++ = ((*y2++ >> rloss) << rshift) | ((*u++ >> gloss) << gshift) | ((*v++ >> bloss) << bshift);
+                }
+                y1 = y2;
+                y2 += width;
+                d32_1 = d32_2;
+                d32_2 += width;
+            }
+            break;
+    }
+}
+
+/*
+ * Python API stuff
+ */
+ 
+PyMethodDef cameraobj_builtins[] =
+{
+    { "start", (PyCFunction) camera_start, METH_NOARGS, DOC_CAMERASTART },
+    { "stop", (PyCFunction) camera_stop, METH_NOARGS, DOC_CAMERASTOP },
+    { "get_controls", (PyCFunction) camera_get_controls, METH_NOARGS, DOC_CAMERAGETCONTROLS },
+    { "set_controls", (PyCFunction) camera_set_controls, METH_KEYWORDS, DOC_CAMERASETCONTROLS },
+    { "get_size", (PyCFunction) camera_get_size, METH_NOARGS, DOC_CAMERAGETSIZE },
+    { "query_image", (PyCFunction) camera_query_image, METH_NOARGS, DOC_CAMERAQUERYIMAGE },
+    { "get_image", (PyCFunction) camera_get_image, METH_VARARGS, DOC_CAMERAGETIMAGE },
+    { "get_raw", (PyCFunction) camera_get_raw, METH_NOARGS, DOC_CAMERAGETRAW },
+    { NULL, NULL, 0, NULL }
+};
+
+void camera_dealloc (PyObject* self)
+{
+    free(((PyCameraObject*) self)->device_name);
+    PyObject_DEL (self);
+}
+
+PyObject* camera_getattr(PyObject* self, char* attrname)
+{
+    return Py_FindMethod(cameraobj_builtins, self, attrname);
+}
+
+PyTypeObject PyCamera_Type =
+{
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "Camera",
+    sizeof(PyCameraObject),
+    0,
+    camera_dealloc,
+    0,
+    camera_getattr,
+    NULL,			/*setattr*/
+    NULL,			/*compare*/
+    NULL,			/*repr*/
+    NULL,			/*as_number*/
+    NULL,			/*as_sequence*/
+    NULL,			/*as_mapping*/
+    (hashfunc)NULL, 		/*hash*/
+    (ternaryfunc)NULL,		/*call*/
+    (reprfunc)NULL, 		/*str*/
+    0L,0L,0L,0L,
+    DOC_PYGAMECAMERACAMERA /* Documentation string */
+};
+
+PyObject* Camera (PyCameraObject* self, PyObject* arg)
+{
+    int w, h;
+    char* dev_name = NULL;
+    char* color = NULL;
+    PyCameraObject *cameraobj;
+    
+    w = DEFAULT_WIDTH;
+    h = DEFAULT_HEIGHT;
+    
+    if (!PyArg_ParseTuple(arg, "s|(ii)s", &dev_name, &w, &h, &color))
+        return NULL;
+    
+    cameraobj = PyObject_NEW (PyCameraObject, &PyCamera_Type);
+    
+    if (cameraobj) {
+        cameraobj->device_name = (char*) malloc((strlen(dev_name)+1)*sizeof(char));
+        strcpy(cameraobj->device_name, dev_name);
+        cameraobj->camera_type = 0;
+        cameraobj->pixelformat = 0;
+        if (color) {
+            if (!strcmp(color, "YUV")) {
+                cameraobj->color_out = YUV_OUT;
+            } else if (!strcmp(color, "HSV")) {
+                cameraobj->color_out = HSV_OUT;
+            } else {
+                cameraobj->color_out = RGB_OUT;
+            }
+        } else {
+            cameraobj->color_out = RGB_OUT;
+        }
+        cameraobj->buffers = NULL;
+        cameraobj->n_buffers = 0;
+        cameraobj->width = w;
+        cameraobj->height = h;
+        cameraobj->size = 0;
+        cameraobj->hflip = 0;
+        cameraobj->vflip = 0;
+        cameraobj->brightness = 0;
+        cameraobj->fd = -1;
+    }
+    
+    return (PyObject*)cameraobj;
+}
+
+PyMethodDef camera_builtins[] =
+{
+    { "colorspace", surf_colorspace, METH_VARARGS, DOC_PYGAMECAMERACOLORSPACE },
+    { "list_cameras", list_cameras, METH_NOARGS, DOC_PYGAMECAMERALISTCAMERAS },
+    { "Camera", (PyCFunction) Camera, METH_VARARGS, DOC_PYGAMECAMERACAMERA },
+    { NULL, NULL, 0, NULL }
+};
+ 
+void init_camera(void)
+{
+  PyObject *module, *dict;
+  /* imported needed apis; Do this first so if there is an error
+     the module is not loaded.
+  */
+  import_pygame_base ();
+  if (PyErr_Occurred ()) {
+    return;
+  }
+  import_pygame_surface ();
+  if (PyErr_Occurred ()) {
+    return;
+  }
+
+  /* type preparation */
+  PyType_Init(PyCamera_Type);
+  
+  /* create the module */
+  module = Py_InitModule3("_camera", camera_builtins, DOC_PYGAMECAMERA);
+  dict = PyModule_GetDict(module);
+  PyDict_SetItemString(dict, "CameraType", (PyObject *)&PyCamera_Type);
+}

File src/camera.c

-/*
-  pygame - Python Game Library
-
-  This library is free software; you can redistribute it and/or
-  modify it under the terms of the GNU Library General Public
-  License as published by the Free Software Foundation; either
-  version 2 of the License, or (at your option) any later version.
-
-  This library is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  Library General Public License for more details.
-
-  You should have received a copy of the GNU Library General Public
-  License along with this library; if not, write to the Free
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-  
-*/
-
-/*
- * Camera - webcam support for pygame
- * Author: Nirav Patel
- *
- * This module allows for use of v4l2 webcams in pygame.  The code is written
- * such that adding support for v4l or vfw cameras should be possible without
- * much modification of existing functions.  v4l2 functions are kept seperate
- * from functions available to pygame users and generic functions like
- * colorspace conversion.
- *
- * There is currently support for cameras that support MMAP and use pixelformats
- * of RGB24, RGB444, YUYV, SBGGR8, and YUV420.  To add support for additional
- * pixelformats, add them to v4l2_init_device and v4l2_process_image, and add
- * functions to convert the format to packed RGB, YUV, and HSV.
- */
- 
-#include "camera.h"
-
-#if defined(__unix__)
-#else
-    #define V4L2_PIX_FMT_RGB24 1
-    #define V4L2_PIX_FMT_RGB444 1
-#endif
-
-/* functions available to pygame users */
-PyObject* surf_colorspace (PyObject* self, PyObject* arg);
-PyObject* list_cameras (PyObject* self, PyObject* arg);
-PyObject* camera_start (PyCameraObject* self);
-PyObject* camera_stop (PyCameraObject* self);
-PyObject* camera_get_controls (PyCameraObject* self);
-PyObject* camera_set_controls (PyCameraObject* self, PyObject* arg, PyObject *kwds);
-PyObject* camera_get_size (PyCameraObject* self);
-PyObject* camera_query_image (PyCameraObject* self);
-PyObject* camera_get_image (PyCameraObject* self, PyObject* arg);
-PyObject* camera_get_raw(PyCameraObject* self);
-
-/*
- * Functions available to pygame users.  The idea is to make these as simple as
- * possible, and merely have them call functions specific to the type of 
- * camera being used to do all the real work.  It currently just calls v4l2_*
- * functions, but it could check something like self->cameratype and depending
- * on the result, call v4l, v4l2, vfw, or other functions.
- */
-
-/* colorspace() - Surface colorspace conversion */
-PyObject* surf_colorspace (PyObject* self, PyObject* arg)
-{
-    PyObject *surfobj, *surfobj2;
-    SDL_Surface* surf, *newsurf;
-    char* color;
-    int cspace;
-    surfobj2 = NULL;
-
-    /*get all the arguments*/
-    if (!PyArg_ParseTuple (arg, "O!s|O!", &PySurface_Type, &surfobj, 
-                           &color, &PySurface_Type, &surfobj2))
-        return NULL;
-
-    if (!strcmp(color, "YUV")) {
-        cspace = YUV_OUT;
-    } else if (!strcmp(color, "HSV")) {
-        cspace = HSV_OUT;
-    } else {
-        return RAISE (PyExc_ValueError, "Incorrect colorspace value");
-    }
-
-    surf = PySurface_AsSurface (surfobj);
-	
-    if (!surfobj2) {
-        newsurf = SDL_CreateRGBSurface (0, surf->w, surf->h,
-            surf->format->BitsPerPixel, surf->format->Rmask,
-            surf->format->Gmask, surf->format->Bmask, surf->format->Amask);
-        if (!newsurf) {
-            return NULL;
-        }
-    } else {
-        newsurf = PySurface_AsSurface (surfobj2);
-    }
-
-    /* check to see if the size is the same. */
-    if (newsurf->w != surf->w || newsurf->h != surf->h)
-        return RAISE (PyExc_ValueError, 
-                      "Surfaces not the same width and height.");
-
-    /* check to see if the format of the surface is the same. */
-    if (surf->format->BitsPerPixel != newsurf->format->BitsPerPixel)
-        return RAISE (PyExc_ValueError, "Surfaces not the same depth");
-
-    SDL_LockSurface (newsurf);
-    PySurface_Lock (surfobj);
-
-    Py_BEGIN_ALLOW_THREADS;
-    colorspace (surf, newsurf, cspace);
-    Py_END_ALLOW_THREADS;
-
-    PySurface_Unlock (surfobj);
-    SDL_UnlockSurface (newsurf);
-
-    if (surfobj2)
-    {
-        Py_INCREF (surfobj2);
-        return surfobj2;
-    }
-    else
-        return PySurface_New (newsurf);
-}
-
-/* list_cameras() - lists cameras available on the computer */
-PyObject* list_cameras (PyObject* self, PyObject* arg)
-{
-#if defined(__unix__)
-    PyObject* ret_list;
-    PyObject* string;
-    char** devices;
-    int num_devices, i;
-    
-    num_devices = 0;
-    ret_list = NULL;
-    ret_list = PyList_New (0);
-    if (!ret_list)
-        return NULL;
-
-    devices = v4l2_list_cameras(&num_devices);
-    
-    for(i = 0; i < num_devices; i++) {
-        string = PyString_FromString(devices[i]);
-        PyList_Append(ret_list, string);
-        Py_DECREF(string);
-        free(devices[i]);
-    }
-    free(devices);
-    
-    return ret_list;
-#else
-	Py_RETURN_NONE;
-#endif
-}
-
-/* start() - opens, inits, and starts capturing on the camera */
-PyObject* camera_start (PyCameraObject* self)
-{
-#if defined(__unix__)
-    if (v4l2_open_device(self) == 0) {
-        if (v4l_open_device(self) == 0) {
-            v4l2_close_device(self);
-            return NULL;
-        } else {
-            self->camera_type = CAM_V4L;
-            if (v4l_init_device(self) == 0) {
-                v4l2_close_device(self);
-                return NULL;
-            }
-            if (v4l_start_capturing(self) == 0) {
-                v4l2_close_device(self);
-                return NULL;
-            }
-        }
-    } else {
-        self->camera_type = CAM_V4L2;
-        if (v4l2_init_device(self) == 0) {
-            v4l2_close_device(self);
-            return NULL;
-        }
-        if (v4l2_start_capturing(self) == 0) {
-            v4l2_close_device(self);
-            return NULL;
-        }
-    }
-#endif
-    Py_RETURN_NONE;
-}
-
-/* stop() - stops capturing, uninits, and closes the camera */
-PyObject* camera_stop (PyCameraObject* self)
-{
-#if defined(__unix__)
-    if (v4l2_stop_capturing(self) == 0)
-        return NULL;
-    if (v4l2_uninit_device(self) == 0)
-        return NULL;
-    if (v4l2_close_device(self) == 0)
-        return NULL;
-#endif
-    Py_RETURN_NONE;
-}
-
-/* get_controls() - gets current values of user controls */
-/* TODO: Support brightness, contrast, and other common controls */
-PyObject* camera_get_controls (PyCameraObject* self)
-{
-    int value;
-#if defined(__unix__)    
-    if (v4l2_get_control(self->fd, V4L2_CID_HFLIP, &value))
-        self->hflip = value;
-    
-    if (v4l2_get_control(self->fd, V4L2_CID_VFLIP, &value))
-        self->vflip = value;
-
-    if (v4l2_get_control(self->fd, V4L2_CID_BRIGHTNESS, &value))
-        self->brightness = value;
-#endif    
-    return Py_BuildValue ("(NNN)", PyBool_FromLong(self->hflip), PyBool_FromLong(self->vflip), PyInt_FromLong(self->brightness));
-}
-
-/* set_controls() - changes camera settings if supported by the camera */
-PyObject* camera_set_controls (PyCameraObject* self, PyObject* arg, PyObject *kwds)
-{
-    int hflip = 0, vflip = 0, brightness = 0;
-    char *kwids[] = {"hflip", "vflip", "brightness", NULL};
-
-    camera_get_controls(self);
-    hflip = self->hflip;
-    vflip = self->vflip;
-    brightness = self->brightness;
-    
-    if (!PyArg_ParseTupleAndKeywords(arg, kwds, "|iii", kwids, &hflip, &vflip, &brightness))
-        return NULL;
-#if defined(__unix__)        
-    if (v4l2_set_control(self->fd, V4L2_CID_HFLIP, hflip))
-        self->hflip = hflip;
-        
-    if (v4l2_set_control(self->fd, V4L2_CID_VFLIP, vflip))
-        self->vflip = vflip;
-        
-    if (v4l2_set_control(self->fd, V4L2_CID_BRIGHTNESS, brightness))
-        self->brightness = brightness;
-#endif    
-    return Py_BuildValue ("(NNN)", PyBool_FromLong(self->hflip), PyBool_FromLong(self->vflip), PyInt_FromLong(self->brightness));
-}
-
-/* get_size() - returns the dimensions of the images being recorded */
-PyObject* camera_get_size (PyCameraObject* self)
-{
-    return Py_BuildValue ("(ii)", self->width, self->height);
-}
-
-/* query_image() - checks if a frame is ready */
-PyObject* camera_query_image (PyCameraObject* self)
-{
-#if defined(__unix__)
-    return PyBool_FromLong(v4l2_query_buffer(self));
-#endif
-    Py_RETURN_NONE;
-}
-
-/* get_image() - returns an RGB Surface */
-/* code to reuse Surface from René Dudfield */
-PyObject* camera_get_image (PyCameraObject* self, PyObject* arg)
-{
-    SDL_Surface* surf = NULL;
-    PyObject *surfobj = NULL;
-    
-    if (!PyArg_ParseTuple (arg, "|O!", &PySurface_Type, &surfobj))
-        return NULL;
-
-    if (!surfobj) {
-        surf = SDL_CreateRGBSurface (0, self->width, self->height, 24, 0xFF<<16, 
-                                 0xFF<<8, 0xFF, 0);
-    } else {
-        surf = PySurface_AsSurface (surfobj);
-    }
-    
-    if (!surf)
-        return NULL;
-        
-    if (surf->w != self->width || surf->h != self->height) {
-        return RAISE (PyExc_ValueError, 
-                      "Destination surface not the correct width or height.");
-    }
-#if defined(__unix__)
-    Py_BEGIN_ALLOW_THREADS;
-    if (!v4l2_read_frame(self, surf))
-        return NULL;
-    Py_END_ALLOW_THREADS;
-#endif
-    if (!surf)
-        return NULL;
-        
-    if (surfobj) {
-        Py_INCREF (surfobj);
-        return surfobj;
-    } else {
-        return PySurface_New (surf);
-    }
-}
-
-/* get_raw() - returns an unmodified image as a string from the buffer */
-PyObject* camera_get_raw(PyCameraObject* self)
-{
-#if defined(__unix__)
-    return v4l2_read_raw(self);
-#endif
-    Py_RETURN_NONE;
-}
-
-/*
- * Pixelformat conversion functions
- */
- 
-/* converts from rgb Surface to yuv or hsv */
-/* TODO: Allow for conversion from yuv and hsv to all */
-void colorspace (SDL_Surface *src, SDL_Surface *dst, int cspace)
-{   
-    switch (cspace) {
-        case YUV_OUT:
-            rgb_to_yuv (src->pixels, dst->pixels, src->h * src->w, 0, src->format);
-            break;
-        case HSV_OUT:
-            rgb_to_hsv (src->pixels, dst->pixels, src->h * src->w, 0, src->format);
-            break;
-    }
-}
-
-/* converts pretty directly if its already RGB24 */
-void rgb24_to_rgb (const void* src, void* dst, int length, SDL_PixelFormat* format)
-{
-    Uint8 *s = (Uint8 *) src;
-    Uint8 *d8;
-    Uint16 *d16;
-    Uint32 *d32;
-    Uint8 r, g, b;
-    int rshift, gshift, bshift, rloss, gloss, bloss;
-
-    rshift = format->Rshift;
-    gshift = format->Gshift;
-    bshift = format->Bshift;
-    rloss = format->Rloss;
-    gloss = format->Gloss;
-    bloss = format->Bloss;
-
-    switch (format->BytesPerPixel) {
-        case 1:
-            d8 = (Uint8 *) dst;
-            while (length--) {
-                r = *s++;
-                g = *s++;
-                b = *s++;
-                *d8++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
-            }
-            break;
-        case 2:
-            d16 = (Uint16 *) dst;
-            while (length--) {
-                r = *s++;
-                g = *s++;
-                b = *s++;
-                *d16++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
-            }
-            break;
-        case 3:
-            d8 = (Uint8 *) dst;
-            while (length--) {
-                *d8++ = *(s+2); /* blue */
-                *d8++ = *(s+1); /* green */
-                *d8++ = *s; /* red */
-                s += 3;
-            }
-            break;
-        default:
-            d32 = (Uint32 *) dst;
-            while (length--) {
-                r = *s++;
-                g = *s++;
-                b = *s++;
-                *d32++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
-            }
-            break;
-    }
-}
-
-/* converts packed rgb to packed hsv. formulas modified from wikipedia */
-void rgb_to_hsv (const void* src, void* dst, int length, 
-                 unsigned long source, SDL_PixelFormat* format)
-{
-    Uint8 *s8, *d8;
-    Uint16 *s16, *d16;
-    Uint32 *s32, *d32;
-    Uint8 r, g, b, p1, p2, h, s, v, max, min, delta;
-    int rshift, gshift, bshift, rloss, gloss, bloss;
-
-    s8 = (Uint8 *) src;
-    s16 = (Uint16 *) src;
-    s32 = (Uint32 *) src;
-    d8 = (Uint8 *) dst;
-    d16 = (Uint16 *) dst;
-    d32 = (Uint32 *) dst;
-    rshift = format->Rshift;
-    gshift = format->Gshift;
-    bshift = format->Bshift;
-    rloss = format->Rloss;
-    gloss = format->Gloss;
-    bloss = format->Bloss;
-    
-    /* you could stick the if statement inside the loop, but I'm sacrificing a
-       a few hundred bytes for a little performance */
-    if (source == V4L2_PIX_FMT_RGB444) {
-        while (length--) {
-            p1 = *s8++;
-            p2 = *s8++;
-            b = p2 << 4;
-            g = p1 & 0xF0;
-            r = p1 << 4;
-            max = MAX(MAX(r, g), b);
-            min = MIN(MIN(r, g), b);
-            delta = max - min;
-            v = max; /* value (similar to luminosity) */
-            if (!delta) { /* grey, zero hue and saturation */
-                s = 0;
-                h = 0;
-            } else {
-                s = 255*delta/max; /* saturation */
-                if (r == max) {  /* set hue based on max color */
-                    h = 43*(g - b)/delta;
-                } else if (g == max) {
-                    h = 85 + 43*(b - r)/delta;
-                } else {
-                    h = 170 + 43*(r - g)/delta;
-                }
-            }
-            switch (format->BytesPerPixel) {
-                case 1:
-                   *d8++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-                case 2:
-                   *d16++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-                case 3:
-                   *d8++ = v;
-                   *d8++ = s;
-                   *d8++ = h;
-                   break;
-                default:
-                   *d32++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-            }
-        }
-    } else if (source == V4L2_PIX_FMT_RGB24) {
-        while (length--) {
-            r = *s8++;
-            g = *s8++;
-            b = *s8++;
-            max = MAX(MAX(r, g), b);
-            min = MIN(MIN(r, g), b);
-            delta = max - min;
-            v = max; /* value (similar to luminosity) */
-            if (!delta) { /* grey, zero hue and saturation */
-                s = 0;
-                h = 0;
-            } else {
-                s = 255*delta/max; /* saturation */
-                if (r == max) {  /* set hue based on max color */
-                    h = 43*(g - b)/delta;
-                } else if (g == max) {
-                    h = 85 + 43*(b - r)/delta;
-                } else {
-                    h = 170 + 43*(r - g)/delta;
-                }
-            }
-            switch (format->BytesPerPixel) {
-                case 1:
-                   *d8++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-                case 2:
-                   *d16++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-                case 3:
-                   *d8++ = v;
-                   *d8++ = s;
-                   *d8++ = h;
-                   break;
-                default:
-                   *d32++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-            }
-        }
-    } else { /* for use as stage 2 in yuv or bayer to hsv, r and b switched */
-        while (length--) {
-            switch (format->BytesPerPixel) {
-                case 1:
-                   r = *s8 >> rshift << rloss;
-                   g = *s8 >> gshift << gloss;
-                   b = *s8++ >> bshift << bloss;
-                   break;
-                case 2:
-                   r = *s16 >> rshift << rloss;
-                   g = *s16 >> gshift << gloss;
-                   b = *s16++ >> bshift << bloss;
-                   break;
-                case 3:
-                   b = *s8++;
-                   g = *s8++;
-                   r = *s8++;
-                   break;
-                default:
-                   r = *s32 >> rshift << rloss;
-                   g = *s32 >> gshift << gloss;
-                   b = *s32++ >> bshift << bloss;
-                   break;
-            }
-            max = MAX(MAX(r, g), b);
-            min = MIN(MIN(r, g), b);
-            delta = max - min;
-            v = max; /* value (similar to luminosity) */
-            if (!delta) { /* grey, zero hue and saturation */
-                s = 0;
-                h = 0;
-            } else {
-                s = 255*delta/max; /* saturation */
-                if (r == max) {  /* set hue based on max color */
-                    h = 43*(g - b)/delta;
-                } else if (g == max) {
-                    h = 85 + 43*(b - r)/delta;
-                } else {
-                    h = 170 + 43*(r - g)/delta;
-                }
-            }
-            switch (format->BytesPerPixel) {
-                case 1:
-                   *d8++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-                case 2:
-                   *d16++ = ((h >> rloss) << rshift) + ((s >> gloss) << gshift) + ((v >> bloss) << bshift);
-                   break;
-                case 3:
-                   *d8++ = v;
-                   *d8++ = s;
-                   *d8++ = h;
-                   break;
-                default:
-                   *d32++ = ((h >> rloss) << rshift) | ((s >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-            }
-        }
-    }
-}
-
-/* convert packed rgb to yuv. Note that unlike many implementations of YUV,
-   this has a full range of 0-255 for Y, not 16-235. Formulas from wikipedia */
-void rgb_to_yuv (const void* src, void* dst, int length, 
-                 unsigned long source, SDL_PixelFormat* format)
-{
-    Uint8 *s8, *d8;
-    Uint16 *s16, *d16;
-    Uint32 *s32, *d32;
-    Uint8 r, g, b, y, u, v;
-    Uint8 p1, p2;
-    int rshift, gshift, bshift, rloss, gloss, bloss;
-
-    s8 = (Uint8 *) src;
-    s16 = (Uint16 *) src;
-    s32 = (Uint32 *) src;
-    d8 = (Uint8 *) dst;
-    d16 = (Uint16 *) dst;
-    d32 = (Uint32 *) dst;
-    rshift = format->Rshift;
-    gshift = format->Gshift;
-    bshift = format->Bshift;
-    rloss = format->Rloss;
-    gloss = format->Gloss;
-    bloss = format->Bloss;
-    
-    if (source == V4L2_PIX_FMT_RGB444) {    
-        while (length--) {
-            p1 = *s8++;
-            p2 = *s8++;
-            b = p2 << 4;
-            g = p1 & 0xF0;
-            r = p1 << 4;
-            v = ((112*r-94*g-18*b + 128) >> 8) + 128;  /* V */
-            u = ((-38*r-74*g+112*b + 128) >> 8) + 128; /* U */
-            y = (77*r+150*g+29*b + 128) >> 8; /* Y */
-            switch (format->BytesPerPixel) {
-                case 1:
-                   *d8++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-                case 2:
-                   *d16++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-                case 3:
-                   *d8++ = v;
-                   *d8++ = u;
-                   *d8++ = y;
-                   break;
-                default:
-                   *d32++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-            }
-        }
-    } else if (source == V4L2_PIX_FMT_RGB24) {
-        while (length--) {
-            r = *s8++;
-            g = *s8++;
-            b = *s8++;
-            v = ((112*r-94*g-18*b + 128) >> 8) + 128;  /* V */
-            u = ((-38*r-74*g+112*b + 128) >> 8) + 128; /* U */
-            y = (77*r+150*g+29*b + 128) >> 8; /* Y */
-            switch (format->BytesPerPixel) {
-                case 1:
-                   *d8++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-                case 2:
-                   *d16++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-                case 3:
-                   *d8++ = v;
-                   *d8++ = u;
-                   *d8++ = y;
-                   break;
-                default:
-                   *d32++ = ((y >> rloss) << rshift) | ((u >> gloss) << gshift) | ((v >> bloss) << bshift);
-                   break;
-            }
-        }
-    } else { /* for use as stage 2 in bayer to yuv, r and b switched */
-        switch (format->BytesPerPixel) {
-            case 1:
-                while (length--) {
-                    r = *s8 >> rshift << rloss;
-                    g = *s8 >> gshift << gloss;
-                    b = *s8++ >> bshift << bloss;
-                    *d8++ = ((((77*r+150*g+29*b + 128) >> 8) >> rloss) << rshift) | (((((-38*r-74*g+112*b + 128) >> 8) + 128) >> gloss) << gshift) | (((((112*r-94*g-18*b + 128) >> 8) + 128) >> bloss) << bshift);
-                }
-                break;
-            case 2:
-                while (length--) {
-                    r = *s16 >> rshift << rloss;
-                    g = *s16 >> gshift << gloss;
-                    b = *s16++ >> bshift << bloss;
-                    *d16++ = ((((77*r+150*g+29*b + 128) >> 8) >> rloss) << rshift) | (((((-38*r-74*g+112*b + 128) >> 8) + 128) >> gloss) << gshift) | (((((112*r-94*g-18*b + 128) >> 8) + 128) >> bloss) << bshift);
-                }
-                break;
-            case 3:
-                while (length--) {
-                    b = *s8++;
-                    g = *s8++;
-                    r = *s8++;
-                    *d8++ = ((112*r-94*g-18*b + 128) >> 8) + 128;
-                    *d8++ = ((-38*r-74*g+112*b + 128) >> 8) + 128;
-                    *d8++ = (77*r+150*g+29*b + 128) >> 8;
-                }
-                break;
-            default:
-                while (length--) {
-                    r = *s32 >> rshift << rloss;
-                    g = *s32 >> gshift << gloss;
-                    b = *s32++ >> bshift << bloss;
-                    *d32++ = ((((77*r+150*g+29*b + 128) >> 8) >> rloss) << rshift) | (((((-38*r-74*g+112*b + 128) >> 8) + 128) >> gloss) << gshift) | (((((112*r-94*g-18*b + 128) >> 8) + 128) >> bloss) << bshift);
-                }
-                break;
-        }
-    }
-}
-
-/* Converts from rgb444 (R444) to rgb24 (RGB3) */
-void rgb444_to_rgb (const void* src, void* dst, int length, SDL_PixelFormat* format)
-{
-    Uint8 *s, *d8;
-    Uint16 *d16;
-    Uint32 *d32;
-    Uint8 p1, p2, r, g, b;
-    int rshift, gshift, bshift, rloss, gloss, bloss;
-    
-    s = (Uint8 *) src;
-    rshift = format->Rshift;
-    gshift = format->Gshift;
-    bshift = format->Bshift;
-    rloss = format->Rloss;
-    gloss = format->Gloss;
-    bloss = format->Bloss;
-    
-    switch (format->BytesPerPixel) {
-        case 1:
-            d8 = (Uint8 *) dst;
-            while (length--) {
-               r = *s << 4;
-               g = *s++ & 0xF0;
-               b = *s++ << 4;
-               *d8++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
-            }
-            break;
-        case 2:
-            d16 = (Uint16 *) dst;
-            while (length--) {
-               r = *s << 4;
-               g = *s++ & 0xF0;
-               b = *s++ << 4;
-               *d16++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
-            }
-            break;
-        case 3:
-            d8 = (Uint8 *) dst;    
-            while (length--) {
-                p1 = *s++;
-                p2 = *s++;
-                *d8++ = p2 << 4; /* blue */
-                *d8++ = p1 & 0xF0; /* green */
-                *d8++ = p1 << 4; /* red */
-            }
-            break;
-        default:
-            d32 = (Uint32 *) dst;
-            while (length--) {
-               r = *s << 4;
-               g = *s++ & 0xF0;
-               b = *s++ << 4;
-               *d32++ = ((r >> rloss) << rshift) | ((g >> gloss) << gshift) | ((b >> bloss) << bshift);
-            }
-            break;
-    }
-}   
-
-/* convert from 4:2:2 YUYV interlaced to RGB24 */
-/* modified from OpenCV, based on ccvt_yuyv_bgr32() from camstream */
-void yuyv_to_rgb (const void* src, void* dst, int length, SDL_PixelFormat* format)
-{
-    Uint8 *s, *d8;
-    Uint16 *d16;
-    Uint32 *d32;
-    int i, cb, cg, cr;
-    Uint8 r1, g1, b1, r2, b2, g2, y1, y2;
-    int rshift, gshift, bshift, rloss, gloss, bloss;
-
-    rshift = format->Rshift;
-    gshift = format->Gshift;
-    bshift = format->Bshift;
-    rloss = format->Rloss;
-    gloss = format->Gloss;
-    bloss = format->Bloss;
-    
-    d8 = (Uint8 *) dst;
-    d16 = (Uint16 *) dst;
-    d32 = (Uint32 *) dst;
-    i = length >> 1;
-    s = (Uint8 *) src;
-
-    while (i--) {
-        y1 = *s++;
-        cb = ((*s - 128) * 454) >> 8;
-        cg = (*s++ - 128) * 88;
-        y2 = *s++;
-        cr = ((*s - 128) * 359) >> 8;
-        cg = (cg + (*s++ - 128) * 183) >> 8;
-
-        r1 = SAT2(y1 + cr);
-        b1 = SAT2(y1 + cb);
-        g1 = SAT2(y1 - cg);
-
-        r2 = SAT2(y2 + cr);
-        b2 = SAT2(y2 + cb);
-        g2 = SAT2(y2 - cg);
-        switch (format->BytesPerPixel) {
-            case 1:
-               *d8++ = ((r1 >> rloss) << rshift) | ((g1 >> gloss) << gshift) | ((b1 >> bloss) << bshift);
-               *d8++ = ((r2 >> rloss) << rshift) | ((g2 >> gloss) << gshift) | ((b2 >> bloss) << bshift);
-               break;
-            case 2:
-               *d16++ = ((r1 >> rloss) << rshift) | ((g1 >> gloss) << gshift) | ((b1 >> bloss) << bshift);
-               *d16++ = ((r2 >> rloss) << rshift) | ((g2 >> gloss) << gshift) | ((b2 >> bloss) << bshift);
-               break;