Nirav Patel avatar Nirav Patel committed 1ca45b5

camera module with v4l2 support and colorspace conversion

Comments (0)

Files changed (35)

 _numericsurfarray src/_numericsurfarray.c $(SDL) $(DEBUG)
 _numericsndarray src/_numericsndarray.c $(SDL) $(MIXER) $(DEBUG)
 movie src/movie.c $(SDL) $(SMPEG) $(DEBUG)
-scrap src/scrap.c $(SDL) $(SCRAP) $(DEBUG)
+scrap src/scrap.c $(SDL) $(SCRAP) $(DEBUG)
+camera src/camera.c src/camera_v4l2.c src/camera_v4l.c $(SDL) $(DEBUG)
 
 #experimental new movie movie. requires libavcodec and libavformat.
 #add any necessary compile flags to this line and uncomment.

docs/ref/camera.html

+
+<html>
+<title>camera - Pygame Documentation</title>
+<body bgcolor=#aaeebb text=#000000 link=#331111 vlink=#331111>
+
+
+<table cellpadding=0 cellspacing=0 border=0 style='border: 3px solid black;' width='100%'>
+<tr>
+<td bgcolor='#c2fc20' style='padding: 6px;' align=center valign=center><a href='http://www.pygame.org/'><img src='../pygame_tiny.gif' border=0 width=200 height=60></a><br><b>pygame documentation</b></td>
+<td bgcolor='#6aee28' style='border-left: 3px solid black; padding: 6px;' align=center valign=center>
+	||&nbsp;
+	<a href=http://www.pygame.org>Pygame Home</a> &nbsp;||&nbsp;
+	<a href=../index.html>Help Contents</a> &nbsp;||
+	<a href=index.html>Reference Index</a> &nbsp;||
+	<br>&nbsp;<br>
+	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
+<a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
+<a href="color.html">Color</a>&nbsp;||&nbsp;
+<a href="cursors.html">Cursors</a>&nbsp;||&nbsp;
+<a href="display.html">Display</a>&nbsp;||&nbsp;
+<a href="draw.html">Draw</a>&nbsp;||&nbsp;
+<a href="event.html">Event</a>&nbsp;||&nbsp;
+<a href="font.html">Font</a>&nbsp;||&nbsp;
+<a href="image.html">Image</a>&nbsp;||&nbsp;
+<a href="joystick.html">Joystick</a>&nbsp;||&nbsp;
+<a href="key.html">Key</a>&nbsp;||&nbsp;
+<a href="mask.html">Mask</a>&nbsp;||&nbsp;
+<a href="mixer.html">Mixer</a>&nbsp;||&nbsp;
+<a href="mouse.html">Mouse</a>&nbsp;||&nbsp;
+<a href="movie.html">Movie</a>&nbsp;||&nbsp;
+<a href="music.html">Music</a>&nbsp;||&nbsp;
+<a href="overlay.html">Overlay</a>&nbsp;||&nbsp;
+<a href="pixelarray.html">Pixelarray</a>&nbsp;||&nbsp;
+<a href="pygame.html">Pygame</a>&nbsp;||&nbsp;
+<a href="rect.html">Rect</a>&nbsp;||&nbsp;
+<a href="scrap.html">Scrap</a>&nbsp;||&nbsp;
+<a href="sndarray.html">Sndarray</a>&nbsp;||&nbsp;
+<a href="sprite.html">Sprite</a>&nbsp;||&nbsp;
+<a href="surface.html">Surface</a>&nbsp;||&nbsp;
+<a href="surfarray.html">Surfarray</a>&nbsp;||&nbsp;
+<a href="time.html">Time</a>&nbsp;||&nbsp;
+<a href="transform.html">Transform</a>
+</td></tr></table>
+<br>
+
+
+<a name="pygame.camera">
+<big><b>pygame.camera</big></b><br><ul>
+  <i>pygame module for camera use</i><br>
+<ul><small><table>
+  <tr><td><a href="camera.html#pygame.camera.colorspace">pygame.camera.colorspace</a> - <font size=-1>Surface colorspace conversion</font></td><td>Surface colorspace conversion</td></tr>
+  <tr><td><a href="camera.html#pygame.camera.list_cameras">pygame.camera.list_cameras</a> - <font size=-1>returns a list of available cameras</font></td><td>returns a list of available cameras</td></tr>
+  <tr><td><a href="camera.html#pygame.camera.Camera">pygame.camera.Camera</a> - <font size=-1>load a camera</font></td><td>load a camera</td></tr>
+</table></small></ul>
+<p>Pygame currently supports only Linux and v4l2 cameras. </p>
+<!--COMMENTS:pygame.camera--> &nbsp;<br> 
+
+
+<a name="pygame.camera.colorspace">
+<big><b>pygame.camera.colorspace</big></b><br><ul>
+  <i>Surface colorspace conversion</i><br>
+  <tt>pygame.camera.colorspace(Surface, format, DestSurface = None): return Surface</tt><br>
+<p>Allows for conversion from <tt>"RGB"</tt> to a destination colorspace of <tt>"HSV"</tt> or <tt>"YUV"</tt>. The source and destination surfaces must be the same size and pixel depth. This is useful for computer vision on devices with limited processing power. Capture as small of an image as possible, <tt>transform.scale()</tt> it even smaller, and then convert the colorspace to <tt>YUV</tt> or <tt>HSV</tt> before doing any processing on it. </p>
+<!--COMMENTS:pygame.camera.colorspace--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="pygame.camera.list_cameras">
+<big><b>pygame.camera.list_cameras</big></b><br><ul>
+  <i>returns a list of available cameras</i><br>
+  <tt>pygame.camera.list_cameras(): return [cameras]</tt><br>
+<p>Checks the computer for available cameras and returns a list of strings of camera names, ready to be fed into <tt>pygame.camera.Camera</tt>. </p>
+<!--COMMENTS:pygame.camera.list_cameras--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="pygame.camera.Camera">
+<big><b>pygame.camera.Camera</big></b><br><ul>
+  <i>load a camera</i><br>
+  <tt>pygame.camera.Camera(device, (width, height), format): return Camera</tt><br>
+<ul><small><table>
+  <tr><td><a href="camera.html#Camera.start">Camera.start</a> - <font size=-1>opens, initializes, and starts capturing</font></td><td>opens, initializes, and starts capturing</td></tr>
+  <tr><td><a href="camera.html#Camera.stop">Camera.stop</a> - <font size=-1>stops, uninitializes, and closes the camera</font></td><td>stops, uninitializes, and closes the camera</td></tr>
+  <tr><td><a href="camera.html#Camera.get_controls">Camera.get_controls</a> - <font size=-1>gets current values of user controls</font></td><td>gets current values of user controls</td></tr>
+  <tr><td><a href="camera.html#Camera.set_controls">Camera.set_controls</a> - <font size=-1>changes camera settings if supported by the camera</font></td><td>changes camera settings if supported by the camera</td></tr>
+  <tr><td><a href="camera.html#Camera.get_size">Camera.get_size</a> - <font size=-1>returns the dimensions of the images being recorded</font></td><td>returns the dimensions of the images being recorded</td></tr>
+  <tr><td><a href="camera.html#Camera.query_image">Camera.query_image</a> - <font size=-1>checks if a frame is ready</font></td><td>checks if a frame is ready</td></tr>
+  <tr><td><a href="camera.html#Camera.get_image">Camera.get_image</a> - <font size=-1>captures an image as a Surface</font></td><td>captures an image as a Surface</td></tr>
+  <tr><td><a href="camera.html#Camera.get_raw">Camera.get_raw</a> - <font size=-1>returns an unmodified image as a string</font></td><td>returns an unmodified image as a string</td></tr>
+</table></small></ul>
+<p>Loads a v4l2 camera. The device is typically something like "/dev/video0". Default width and height are 640 by 480. Format is the desired colorspace of the output. This is useful for computer vision purposes. The following are supported: </p>
+<ul>
+ <li> RGB - Red, Green, Blue </li>
+ <li> YUV - Luma, Blue Chrominance, Red Chrominance </li>
+ <li> HSV - Hue, Saturation, Value </li>
+</ul>
+<!--COMMENTS:pygame.camera.Camera--> &nbsp;<br> 
+
+
+<a name="Camera.start">
+<big><b>Camera.start</big></b><br><ul>
+  <i>opens, initializes, and starts capturing</i><br>
+  <tt>Camera.start(): return None</tt><br>
+<p>Opens the camera device, attempts to initialize it, and begins recording images to a buffer. </p>
+<!--COMMENTS:Camera.start--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Camera.stop">
+<big><b>Camera.stop</big></b><br><ul>
+  <i>stops, uninitializes, and closes the camera</i><br>
+  <tt>Camera.stop(): return None</tt><br>
+<p>Stops recording, uninitializes the camera, and closes it. </p>
+<!--COMMENTS:Camera.stop--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Camera.get_controls">
+<big><b>Camera.get_controls</big></b><br><ul>
+  <i>gets current values of user controls</i><br>
+  <tt>Camera.get_controls(): return (hflip = bool, vflip = bool)</tt><br>
+<p>If the camera supports it, get_controls will return the current settings for horizontal and vertical image flip as bools. If unsupported, it will return the default values of (0, 0). Note that the return values here may be different than those returned by set_controls, though these are more likely to be correct. </p>
+<!--COMMENTS:Camera.get_controls--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Camera.set_controls">
+<big><b>Camera.set_controls</big></b><br><ul>
+  <i>changes camera settings if supported by the camera</i><br>
+  <tt>Camera.set_controls(hflip = bool, vflip = bool): return (hflip = bool, vflip = bool)</tt><br>
+<p>Allows you to change camera settings if the camera supports it. The return values will be the input values if the camera claims it succeeded or the values previously in use if not. Each argument is optional, and the desired one can be chosen by supplying the keyword, like hflip. Note that the actual settings being used by the camera may not be the same as those returned by set_controls. </p>
+<!--COMMENTS:Camera.set_controls--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Camera.get_size">
+<big><b>Camera.get_size</big></b><br><ul>
+  <i>returns the dimensions of the images being recorded</i><br>
+  <tt>Camera.get_size(): return (width, height)</tt><br>
+<p>Returns the current dimensions of the images being captured by the camera. </p>
+<!--COMMENTS:Camera.get_size--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Camera.query_image">
+<big><b>Camera.query_image</big></b><br><ul>
+  <i>checks if a frame is ready</i><br>
+  <tt>Camera.query_image(): return bool</tt><br>
+<p>If an image is ready to get, it returns true. Otherwise it returns false. Note that some webcams will always return False and will only queue a frame when called with a blocking function like get_image(). </p>
+<!--COMMENTS:Camera.query_image--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Camera.get_image">
+<big><b>Camera.get_image</big></b><br><ul>
+  <i>captures an image as a Surface</i><br>
+  <tt>Camera.get_image(Surface = None): return Surface</tt><br>
+<p>Pulls an image off of the buffer as an <tt>RGB</tt> Surface. It can optionally reuse an existing Surface to save time. The bit depth of the surface is either 24bits or the same as the optionally supplied Surface. </p>
+<!--COMMENTS:Camera.get_image--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Camera.get_raw">
+<big><b>Camera.get_raw</big></b><br><ul>
+  <i>returns an unmodified image as a string</i><br>
+  <tt>Camera.get_raw(): return string</tt><br>
+<p>Gets an image from a camera as a string in the native pixelformat of the camera. Useful for integration with other libraries. </p>
+<!--COMMENTS:Camera.get_raw--> &nbsp;<br> 
+<br></ul>
+<br></ul>
+<br></ul>
+
+</body></html>

docs/ref/cdrom.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/color.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/cursors.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/display.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/draw.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/event.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/font.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/image.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/index.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;
 <li><a href="pygame.html#pygame.get_sdl_byteorder">pygame.get_sdl_byteorder</a> - <font size=-1>get the byte order of SDL</font></li>
 <li><a href="pygame.html#pygame.get_sdl_version">pygame.get_sdl_version</a> - <font size=-1>get the version number of SDL</font></li>
 <li><a href="pygame.html#pygame.init">pygame.init</a> - <font size=-1>initialize all imported pygame modules</font></li>
+<li><a href="camera.html#pygame.camera">pygame.camera</a> - <font size=-1>pygame module for camera use</font></li>
+<ul>
+<li><a href="camera.html#pygame.camera.Camera">pygame.camera.Camera</a> - <font size=-1>load a camera</font></li>
+<ul>
+<li><a href="camera.html#Camera.get_controls">Camera.get_controls</a> - <font size=-1>gets current values of user controls</font></li>
+<li><a href="camera.html#Camera.get_image">Camera.get_image</a> - <font size=-1>captures an image as a Surface</font></li>
+<li><a href="camera.html#Camera.get_raw">Camera.get_raw</a> - <font size=-1>returns an unmodified image as a string</font></li>
+<li><a href="camera.html#Camera.get_size">Camera.get_size</a> - <font size=-1>returns the dimensions of the images being recorded</font></li>
+<li><a href="camera.html#Camera.query_image">Camera.query_image</a> - <font size=-1>checks if a frame is ready</font></li>
+<li><a href="camera.html#Camera.set_controls">Camera.set_controls</a> - <font size=-1>changes camera settings if supported by the camera</font></li>
+<li><a href="camera.html#Camera.start">Camera.start</a> - <font size=-1>opens, initializes, and starts capturing</font></li>
+<li><a href="camera.html#Camera.stop">Camera.stop</a> - <font size=-1>stops, uninitializes, and closes the camera</font></li>
+</ul>
+<li><a href="camera.html#pygame.camera.colorspace">pygame.camera.colorspace</a> - <font size=-1>Surface colorspace conversion</font></li>
+<li><a href="camera.html#pygame.camera.list_cameras">pygame.camera.list_cameras</a> - <font size=-1>returns a list of available cameras</font></li>
+</ul>
 <li><a href="cdrom.html#pygame.cdrom">pygame.cdrom</a> - <font size=-1>pygame module for audio cdrom control</font></li>
 <ul>
 <li><a href="cdrom.html#pygame.cdrom.CD">pygame.cdrom.CD</a> - <font size=-1>class to manage a cdrom drive</font></li>

docs/ref/joystick.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/key.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/mask.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/mixer.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/mouse.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/movie.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/music.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/overlay.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/pixelarray.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/pygame.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/rect.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/scrap.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/sndarray.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/sprite.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/surface.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/surfarray.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/time.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;

docs/ref/transform.html

 	<a href=index.html>Reference Index</a> &nbsp;||
 	<br>&nbsp;<br>
 	
+<a href="camera.html">Camera</a>&nbsp;||&nbsp;
 <a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
 <a href="color.html">Color</a>&nbsp;||&nbsp;
 <a href="cursors.html">Cursors</a>&nbsp;||&nbsp;
+/*
+  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;
+#endif    
+    return Py_BuildValue ("(OO)", PyBool_FromLong(self->hflip), PyBool_FromLong(self->vflip));
+}
+
+/* set_controls() - changes camera settings if supported by the camera */
+PyObject* camera_set_controls (PyCameraObject* self, PyObject* arg, PyObject *kwds)
+{
+    int hflip = self->hflip;
+    int vflip = self->vflip;
+    
+    char *kwids[] = {"hflip", "vflip", NULL};
+    if (!PyArg_ParseTupleAndKeywords(arg, kwds, "|ii", kwids, &hflip, &vflip))
+        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;
+#endif    
+    return Py_BuildValue ("(OO)", PyBool_FromLong(self->hflip), PyBool_FromLong(self->vflip));
+}
+
+/* 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->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 initcamera(void)
+{
+  PyObject *module, *dict;
+  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);
+  import_pygame_base ();
+  import_pygame_surface ();
+}
+pygame.camera
+pygame module for camera use
+
+Pygame currently supports only Linux and v4l2 cameras.
+<SECTION>
+
+colorspace
+Surface colorspace conversion
+pygame.camera.colorspace(Surface, format, DestSurface = None): return Surface
+
+Allows for conversion from "RGB" to a destination colorspace of "HSV" or "YUV".
+The source and destination surfaces must be the same size and pixel depth.
+This is useful for computer vision on devices with limited processing power.
+Capture as small of an image as possible, transform.scale() it even smaller,
+and then convert the colorspace to YUV or HSV before doing any processing on it.
+<END>
+
+list_cameras
+returns a list of available cameras
+pygame.camera.list_cameras(): return [cameras]
+
+Checks the computer for available cameras and returns a list of strings of
+camera names, ready to be fed into pygame.camera.Camera.
+<END>
+
+Camera
+load a camera
+pygame.camera.Camera(device, (width, height), format): return Camera
+
+Loads a v4l2 camera.  The device is typically something like "/dev/video0".
+Default width and height are 640 by 480.  Format is the desired colorspace of
+the output.  This is useful for computer vision purposes.  The following are
+supported:
+
+* RGB - Red, Green, Blue
+* YUV - Luma, Blue Chrominance, Red Chrominance
+* HSV - Hue, Saturation, Value
+<SECTION>
+
+
+start
+opens, initializes, and starts capturing
+Camera.start(): return None
+
+Opens the camera device, attempts to initialize it, and begins recording
+images to a buffer.
+<END>
+
+
+stop
+stops, uninitializes, and closes the camera
+Camera.stop(): return None
+
+Stops recording, uninitializes the camera, and closes it.
+<END>
+
+
+get_controls
+gets current values of user controls
+Camera.get_controls(): return (hflip = bool, vflip = bool)
+
+If the camera supports it, get_controls will return the current settings for
+horizontal and vertical image flip as bools.  If unsupported, it will return
+the default values of (0, 0).  Note that the return values here may be different
+than those returned by set_controls, though these are more likely to be correct.
+<END>
+
+set_controls
+changes camera settings if supported by the camera
+Camera.set_controls(hflip = bool, vflip = bool): return (hflip = bool, vflip = bool)
+
+Allows you to change camera settings if the camera supports it.  The return
+values will be the input values if the camera claims it succeeded or the values
+previously in use if not.  Each argument is optional, and the desired one
+can be chosen by supplying the keyword, like hflip.  Note that the actual
+settings being used by the camera may not be the same as those returned by
+set_controls.
+<END>
+
+
+get_size
+returns the dimensions of the images being recorded
+Camera.get_size(): return (width, height)
+
+Returns the current dimensions of the images being captured by the camera.
+<END>
+
+query_image
+checks if a frame is ready
+Camera.query_image(): return bool
+
+If an image is ready to get, it returns true.  Otherwise it returns false.  Note
+that some webcams will always return False and will only queue a frame when
+called with a blocking function like get_image().
+<END>
+
+
+get_image
+captures an image as a Surface
+Camera.get_image(Surface = None): return Surface
+
+Pulls an image off of the buffer as an RGB Surface.  It can optionally reuse an 
+existing Surface to save time.  The bit depth of the surface is either 24bits or
+the same as the optionally supplied Surface.
+<END>
+
+
+get_raw
+returns an unmodified image as a string
+Camera.get_raw(): return string
+
+Gets an image from a camera as a string in the native pixelformat of the camera.
+Useful for integration with other libraries.
+<END>
+<END>
+/*
+  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
+  
+*/
+
+#include "pygame.h"
+#include "pygamedocs.h"
+
+#if defined(__unix__)
+    #include <structmember.h>
+    #include <stringobject.h>
+    #include <stdio.h>
+    #include <stdlib.h>
+    #include <string.h>
+    #include <assert.h>
+
+    #include <fcntl.h>              /* low-level i/o */
+    #include <unistd.h>
+    #include <errno.h>
+    #include <sys/stat.h>
+    #include <sys/types.h>
+    #include <sys/time.h>
+    #include <sys/mman.h>
+    #include <sys/ioctl.h>
+
+    #include <asm/types.h>          /* for videodev2.h */
+
+    #include <linux/videodev.h>
+    #include <linux/videodev2.h>
+#endif
+
+#define CLEAR(x) memset (&(x), 0, sizeof (x))
+#define SAT(c) if (c & (~255)) { if (c < 0) c = 0; else c = 255; }
+#define SAT2(c) ((c) & (~255) ? ((c) < 0 ? 0 : 255) : (c))
+#define DEFAULT_WIDTH 640
+#define DEFAULT_HEIGHT 480
+#define RGB_OUT 1
+#define YUV_OUT 2
+#define HSV_OUT 4
+#define CAM_V4L 1
+#define CAM_V4L2 2
+
+struct buffer 
+{
+    void * start;
+    size_t length;
+};
+
+typedef struct
+{
+    PyObject_HEAD
+    char* device_name;
+    int camera_type;
+    unsigned long pixelformat;
+    unsigned int color_out;
+    struct buffer* buffers;
+    unsigned int n_buffers;
+    int width;
+    int height;
+    int size;
+    int hflip;
+    int vflip;
+    int fd;
+} PyCameraObject;
+
+/* internal functions for colorspace conversion */
+void colorspace (SDL_Surface *src, SDL_Surface *dst, int cspace);
+void rgb24_to_rgb (const void* src, void* dst, int length, SDL_PixelFormat* format);
+void rgb444_to_rgb (const void* src, void* dst, int length, SDL_PixelFormat* format);
+void rgb_to_yuv (const void* src, void* dst, int length, 
+                 unsigned long source, SDL_PixelFormat* format);
+void rgb_to_hsv (const void* src, void* dst, int length,
+                 unsigned long source, SDL_PixelFormat* format);
+void yuyv_to_rgb (const void* src, void* dst, int length, SDL_PixelFormat* format);
+void yuyv_to_yuv (const void* src, void* dst, int length, SDL_PixelFormat* format);
+void sbggr8_to_rgb (const void* src, void* dst, int width, int height, SDL_PixelFormat* format);
+void yuv420_to_rgb (const void* src, void* dst, int width, int height, SDL_PixelFormat* format);
+void yuv420_to_yuv (const void* src, void* dst, int width, int height, SDL_PixelFormat* format);
+
+#if defined(__unix__)
+/* internal functions specific to v4l2 */
+char** v4l2_list_cameras (int* num_devices);
+int v4l2_get_control (int fd, int id, int *value);
+int v4l2_set_control (int fd, int id, int value);
+PyObject* v4l2_read_raw (PyCameraObject* self);
+int v4l2_xioctl (int fd, int request, void *arg);
+int v4l2_process_image (PyCameraObject* self, const void *image, 
+                               unsigned int buffer_size, SDL_Surface* surf);
+int v4l2_query_buffer (PyCameraObject* self);
+int v4l2_read_frame (PyCameraObject* self, SDL_Surface* surf);
+int v4l2_stop_capturing (PyCameraObject* self);
+int v4l2_start_capturing (PyCameraObject* self);
+int v4l2_uninit_device (PyCameraObject* self);
+int v4l2_init_mmap (PyCameraObject* self);
+int v4l2_init_device (PyCameraObject* self);
+int v4l2_close_device (PyCameraObject* self);
+int v4l2_open_device (PyCameraObject* self);
+
+/* internal functions specific to v4l */
+int v4l_open_device (PyCameraObject* self);
+int v4l_init_device(PyCameraObject* self);
+int v4l_start_capturing(PyCameraObject* self);
+#endif
+/*
+  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
+  
+*/
+#if defined(__unix__)
+#include "camera.h"
+
+/*
+ * V4L functions
+ */
+ 
+int v4l_open_device (PyCameraObject* self)
+{
+    struct stat st;
+    struct video_capability cap;
+    struct video_mbuf buf;
+    
+    if (-1 == stat (self->device_name, &st)) {
+        PyErr_Format(PyExc_SystemError, "Cannot identify '%s': %d, %s",
+            self->device_name, errno, strerror (errno));
+        return 0;
+    }
+
+    if (!S_ISCHR (st.st_mode)) {
+        PyErr_Format(PyExc_SystemError, "%s is no device",self->device_name);
+        return 0;
+    }
+
+    self->fd = open (self->device_name, O_RDWR /* required | O_NONBLOCK */, 0);
+
+    if (-1 == self->fd) {
+        PyErr_Format(PyExc_SystemError, "Cannot open '%s': %d, %s",
+            self->device_name, errno, strerror (errno));
+        return 0;
+    }
+    
+    if(ioctl(self->fd, VIDIOCGCAP, cap) == -1) {
+        PyErr_Format(PyExc_SystemError, "%s is not a V4L device",
+            self->device_name);        
+	return 0;
+    }
+    
+    if(!(cap.type & VID_TYPE_CAPTURE)) {
+        PyErr_Format(PyExc_SystemError, "%s is not a video capture device",
+            self->device_name);
+        return 0;
+    }
+    
+    if( ioctl(self->fd , VIDIOCGMBUF , buf ) == -1 ) {
+        PyErr_Format(PyExc_SystemError, "%s does not support streaming i/o",
+            self->device_name);
+	return 0;
+    }
+    
+    return 1;
+}
+
+int v4l_init_device(PyCameraObject* self)
+{
+    return 0;
+}
+
+int v4l_start_capturing(PyCameraObject* self)
+{
+    return 0;
+}
+#endif

src/camera_v4l2.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
+  
+*/
+
+#if defined(__unix__)
+
+#include "camera.h"
+
+int v4l2_pixelformat (int fd, struct v4l2_format* fmt, 
+                             unsigned long pixelformat);
+
+char** v4l2_list_cameras (int* num_devices)
+{
+    char** devices;
+    char* device;
+    int num, i, fd;
+    
+    num = *num_devices;
+    
+    devices = (char**) malloc(sizeof(char *)*65);
+    
+    device = (char*) malloc(sizeof(char)*13);
+    strcpy(device,"/dev/video");
+    fd = open(device, O_RDONLY);
+    if (fd != -1) {
+        devices[num] = device;
+        num++;
+        device = (char*) malloc(sizeof(char)*13);
+    }
+    close(fd);
+    /* v4l2 cameras can be /dev/video and /dev/video0 to /dev/video63 */
+    for (i = 0; i < 64; i++) {
+        sprintf(device,"/dev/video%d",i);
+        fd = open(device, O_RDONLY);
+        if (fd != -1) {
+            devices[num] = device;
+            num++;
+            device = (char*) malloc(sizeof(char)*13);
+        }
+        close(fd);
+    }
+    
+    if (num == *num_devices) {
+        free(device);
+    } else {
+        *num_devices = num;
+    }
+    
+    return devices;
+}
+
+/* A wrapper around a VIDIOC_S_FMT ioctl to check for format compatibility */
+int v4l2_pixelformat (int fd, struct v4l2_format* fmt, 
+                             unsigned long pixelformat)
+{
+    fmt->fmt.pix.pixelformat = pixelformat;
+
+    if (-1 == v4l2_xioctl (fd, VIDIOC_S_FMT, fmt)) {
+        return 0;
+    }
+    
+    if (fmt->fmt.pix.pixelformat == pixelformat) {
+    	return 1;
+    } else {
+        return 0;
+    }
+}
+
+/* gets the value of a specific camera control if available */
+int v4l2_get_control (int fd, int id, int *value)
+{
+    struct v4l2_control control;
+    CLEAR(control);
+    
+    control.id = id;
+    
+    if (-1 == v4l2_xioctl (fd, VIDIOC_G_CTRL, &control)) {
+        return 0;
+    }