Index: webcam.h
===================================================================
--- webcam.h	(revision 8629)
+++ webcam.h	(working copy)
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include "mjpeg.h"
 
 #ifndef WIN32
 #include <sys/ioctl.h>
@@ -30,12 +31,6 @@
 #include <vfw.h>
 #endif
 
-
-#define RGB24_LEN(w,h)      ((w) * (h) * 3)
-#define RGB32_LEN(w,h)      ((w) * (h) * 4)
-#define YUV420P_LEN(w,h)    (((w) * (h) * 3) / 2)
-#define YUV422P_LEN(w,h)    ((w) * (h) * 2)
-
 // YUV --> RGB Conversion macros
 #define _S(a)		(a)>255 ? 255 : (a)<0 ? 0 : (a)
 #define _R(y,u,v) (0x2568*(y)  			       + 0x3343*(u)) /0x2000
@@ -43,12 +38,13 @@
 #define _B(y,u,v) (0x2568*(y) + 0x40cf*(v))					     /0x2000
 
 #ifdef WIN32
-#define VIDEO_PALETTE_YUV420P   0
-#define VIDEO_PALETTE_YUV422    1 
-#define VIDEO_PALETTE_YUV422P   2 
-#define VIDEO_PALETTE_RGB32     3
-#define VIDEO_PALETTE_RGB24     4
-#define VIDEO_PALETTE_GREY      5
+#define V4L2_PIX_FMT_YVU420    0
+#define V4L2_PIX_FMT_YUYV      1 
+#define V4L2_PIX_FMT_YUV422P   2 
+#define V4L2_PIX_FMT_BGR32     3
+#define V4L2_PIX_FMT_BGR24     4
+#define V4L2_PIX_FMT_GREY      5
+#define V4L2_PIX_FMT_MJPEG     6
 #endif
 
 
@@ -56,12 +52,13 @@
 #define WCHEIGHT    bitmapInfo.bmiHeader.biHeight
 #define WCWIDTH     bitmapInfo.bmiHeader.biWidth
 #else
-#define WCWIDTH     vWin.width
-#define WCHEIGHT    vWin.height
+#define WCWIDTH     vFormat.fmt.pix.width
+#define WCHEIGHT    vFormat.fmt.pix.height
 #endif
 
 
 #define WC_CLIENT_BUFFERS   2
+#define WC_MMAP_BUFFERS     4
 
 struct wcClient
 {
@@ -117,11 +114,11 @@
     int  SetContrast(int v);
     int  SetColour(int v);
     int  SetHue(int v);
-    int  GetBrightness(void) { return (vPic.brightness);};
-    int  GetColour(void) { return (vPic.colour);};
-    int  GetContrast(void) { return (vPic.contrast);};
-    int  GetHue(void) { return (vPic.hue);};
-    QString GetName(void) { return vCaps.name; };
+    int  GetBrightness(void) { return (brightness.value);};
+    int  GetColour(void) { return (colour.value);};
+    int  GetContrast(void) { return (contrast.value);};
+    int  GetHue(void) { return (hue.value);};
+    QString GetName(void) { return (char *) vCaps.card; };
 #else
     HWND GetHwnd() { return hwndCap; };    
 #endif
@@ -130,8 +127,6 @@
 
     int  SetTargetFps(wcClient *client, int fps);
     int  GetActualFps();
-    void GetMaxSize(int *x, int *y);
-    void GetMinSize(int *x, int *y);
     void GetCurSize(int *x, int *y);
     int isGreyscale(void);
 
@@ -147,6 +142,9 @@
     void StartThread();
     void KillThread();
     void WebcamThreadWorker();
+    void SetupMMAP();
+    void ShutdownMMAP();
+    int ReadFrame(unsigned char *outbuf);
 
 #ifdef WIN32
     HWND hwndCap; 
@@ -166,27 +164,34 @@
     int hDev;
     QString DevName;
     unsigned char *picbuff1;
+    unsigned char *workbuff;
     int imageLen;
     int frameSize;
     int fps;
     int actualFps;
     bool killWebcamThread;
-    int wcFormat;
     bool wcFlip;
 
     QTime cameraTime;
     int frameCount;
     int totalCaptureMs;
 
+    MJPEGContainer *decoder;
+
     // OS specific data structures
 #ifdef WIN32
     CAPTUREPARMS capParams;
     BITMAPINFO bitmapInfo;
 #else
-    struct video_capability vCaps;
-    struct video_window vWin;
-    struct video_picture vPic;
-    struct video_clip vClips;
+    struct v4l2_capability vCaps;
+    struct v4l2_format vFormat;
+    struct v4l2_control brightness;
+    struct v4l2_control contrast;
+    struct v4l2_control colour;
+    struct v4l2_control hue;
+    struct v4l2_clip vClips;
+    void *mmapBuf[WC_MMAP_BUFFERS];
+    v4l2_buffer mmapBufDesc[WC_MMAP_BUFFERS];
 #endif
 
 };
Index: phoneui.cpp
===================================================================
--- phoneui.cpp	(revision 8629)
+++ phoneui.cpp	(working copy)
@@ -140,7 +140,7 @@
             camBrightness = webcam->GetBrightness();
             camContrast = webcam->GetContrast();
             camColour = webcam->GetColour();
-            localClient = webcam->RegisterClient(VIDEO_PALETTE_RGB32, 20, this);
+            localClient = webcam->RegisterClient(V4L2_PIX_FMT_BGR32, 20, this);
         }
     }
 
@@ -545,7 +545,7 @@
     if (h263->H263StartEncoder(txWidth, txHeight, txFps) && 
         h263->H263StartDecoder(rxWidth, rxHeight))
     {
-        txClient = webcam->RegisterClient(VIDEO_PALETTE_YUV420P, txFps, this);
+        txClient = webcam->RegisterClient(V4L2_PIX_FMT_YVU420, txFps, this);
         wcDeliveredFrames = 0;
         wcDroppedFrames = 0;
         VideoOn = true;
Index: mjpeg.h
===================================================================
--- mjpeg.h	(revision 0)
+++ mjpeg.h	(revision 0)
@@ -0,0 +1,43 @@
+/*
+	mjpeg.h
+
+	(c) 2006 Nick Kralevich
+	
+    header for the mjpeg Container class
+*/
+
+#ifndef MJPEG_CONTAINER_H_
+#define MJPEG_CONTAINER_H_
+
+#ifndef WIN32
+#include <mythtv/dialogbox.h>
+#endif
+
+
+extern "C" {
+#ifdef WIN32
+#include "libavcodec/avcodec.h"
+#else
+#include "mythtv/ffmpeg/avcodec.h"
+#endif
+}
+
+
+class MJPEGContainer
+{
+  public:
+    MJPEGContainer(void);
+    virtual ~MJPEGContainer(void);
+
+    bool MJPEGStartDecoder(int w, int h);
+    uchar *MJPEGDecodeFrame(const uchar *mjpegFrame, int mjpegFrameLen, uchar *outbuf, int outbufSize);
+    void MJPEGStopDecoder();
+    int getPixFmt();
+
+  private:
+    AVFrame *pictureIn;
+    AVCodec *mjpegDecoder;
+    AVCodecContext *mjpegDecContext;
+};
+
+#endif
Index: webcam.cpp
===================================================================
--- webcam.cpp	(revision 8629)
+++ webcam.cpp	(working copy)
@@ -3,6 +3,8 @@
 
 	(c) 2003 Paul Volkaerts
 
+	Modifications to support MJPEG, v4l2, and mmaped devices by Nick Kralevich
+
     Webcam control and capture
 */
 #include <qapplication.h>
@@ -20,6 +22,7 @@
 #include <fcntl.h>
 #include <linux/videodev.h>
 #include <mythtv/mythcontext.h>
+#include <sys/mman.h>
 
 #include "config.h"
 #else
@@ -40,32 +43,48 @@
 {
     hDev = 0;
     DevName = "";
-    picbuff1 = 0;
+    picbuff1 = NULL;
+    workbuff = NULL;
     imageLen = 0;
     frameSize = 0;
     fps = 5;
     killWebcamThread = true; // Leave true whilst its not running
-    wcFormat = 0;
     wcFlip = false;
+    decoder = NULL;
 
 #ifndef WIN32
     (void)parent;
     (void)localVideoWidget;
-    vCaps.name[0] = 0;
-    vCaps.maxwidth = 0;
-    vCaps.maxheight = 0;
-    vCaps.minwidth = 0;
-    vCaps.minheight = 0;
-    memset(&vWin, 0, sizeof(struct video_window));
-    vWin.width = 0;
-    vWin.height = 0;
-    vPic.brightness = 0;
-    vPic.depth = 0;
-    vPic.palette = 0;
-    vPic.colour = 0;
-    vPic.contrast = 0;
-    vPic.hue = 0;
+    memset(&vCaps, 0, sizeof(vCaps));
 
+    memset(&vFormat, 0, sizeof(vFormat));
+    vFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    vFormat.fmt.pix.width = 0;
+    vFormat.fmt.pix.height = 0;
+    vFormat.fmt.pix.pixelformat = 0;
+    vFormat.fmt.pix.field = V4L2_FIELD_ANY;
+    vFormat.fmt.pix.bytesperline = 0;
+
+    memset(&brightness, 0, sizeof(brightness));
+    brightness.id = V4L2_CID_BRIGHTNESS;
+    brightness.value = 0;
+
+    memset(&colour, 0, sizeof(colour));
+    colour.id = V4L2_CID_SATURATION;
+    colour.value = 0;
+
+    memset(&contrast, 0, sizeof(contrast));
+    contrast.id = V4L2_CID_CONTRAST;
+    contrast.value = 0;
+
+    memset(&hue, 0, sizeof(hue));
+    hue.id = V4L2_CID_HUE;
+    hue.value = 0;
+
+    for (int i = 0; i < WC_MMAP_BUFFERS; i++) {
+      mmapBuf[i] = NULL;
+      memset(&mmapBufDesc[i], 0, sizeof(mmapBufDesc[i]));
+    }
 #else
     wcMainWidget = parent;
     hwndWebcam = localVideoWidget->winId();
@@ -90,10 +109,10 @@
   if (handle <= 0)
     return "";
   
-  struct video_capability tempCaps;
-  ioctl(handle, VIDIOCGCAP, &tempCaps);
+  struct v4l2_capability tempCaps;
+  ioctl(handle, VIDIOC_QUERYCAP, &tempCaps);
   ::close(handle);
-  return tempCaps.name;
+  return ((char *) tempCaps.card);
 #else
   return "WIN32 Webcam (TODO)"; // TODO
 #endif
@@ -132,11 +151,12 @@
     {
         readCaps();
 
-        if (!SetPalette(VIDEO_PALETTE_YUV420P) && 
-            !SetPalette(VIDEO_PALETTE_YUV422P) &&
-            !SetPalette(VIDEO_PALETTE_RGB24))
+        if (!SetPalette(V4L2_PIX_FMT_YUV420) && 
+            !SetPalette(V4L2_PIX_FMT_YUV422P) &&
+            !SetPalette(V4L2_PIX_FMT_BGR24) && 
+	    !SetPalette(V4L2_PIX_FMT_MJPEG))
         {
-            cout << "Webcam does not support YUV420P, YUV422P, or RGB24 modes; these are the only ones currently supported. Closing webcam.\n";
+            cout << "Webcam does not support YUV420P, YUV422P, RGB24, or MJPEG modes; these are the only ones currently supported. Closing webcam.\n";
             camClose();
             return false;
         }
@@ -153,6 +173,11 @@
             cout << "Could not set webcam to " << width << "x" << height << "; got " << actWidth << "x" << actHeight << " instead.\n";
         }
 
+	if (GetPalette() == V4L2_PIX_FMT_MJPEG) {
+	  decoder = new MJPEGContainer;
+	  decoder->MJPEGStartDecoder(WCWIDTH, WCHEIGHT);
+	}
+
         //Allocate picture buffer memory
         if (isGreyscale())
         {
@@ -165,53 +190,131 @@
         {
             switch (GetPalette())
             {
-            case VIDEO_PALETTE_RGB24:   frameSize = RGB24_LEN(WCWIDTH, WCHEIGHT);   break;
-            case VIDEO_PALETTE_RGB32:   frameSize = RGB32_LEN(WCWIDTH, WCHEIGHT);   break;
-            case VIDEO_PALETTE_YUV420P: frameSize = YUV420P_LEN(WCWIDTH, WCHEIGHT); break;
-            case VIDEO_PALETTE_YUV422P: frameSize = YUV422P_LEN(WCWIDTH, WCHEIGHT); break;
+            case V4L2_PIX_FMT_BGR24:   
+	      frameSize = avpicture_get_size(PIX_FMT_BGR24, WCWIDTH, WCHEIGHT);
+	      break;
+            case V4L2_PIX_FMT_BGR32:   
+	      frameSize = avpicture_get_size(PIX_FMT_RGBA32, WCWIDTH, WCHEIGHT);
+	      break;
+            case V4L2_PIX_FMT_YVU420:  
+	      frameSize = avpicture_get_size(PIX_FMT_YUV420P, WCWIDTH, WCHEIGHT); 
+	      break;
+            case V4L2_PIX_FMT_MJPEG:   
+	      frameSize = avpicture_get_size(PIX_FMT_YUV422P, WCWIDTH, WCHEIGHT); //FIXME
+	      break; 
+            case V4L2_PIX_FMT_YUV422P: 
+	      frameSize = avpicture_get_size(PIX_FMT_YUV422P, WCWIDTH, WCHEIGHT); 
+	      break;
             default:
-                cerr << "Palette mode " << GetPalette() << " not yet supported" << endl;
-                camClose();
-                return false;
-                break;
+	      cerr << "Palette mode " << GetPalette() << " not yet supported" << endl;
+	      camClose();
+	      return false;
+	      break;
             }
 
             picbuff1 = new unsigned char [frameSize];
+            workbuff = new unsigned char [frameSize];
         }
 
-        switch(GetPalette())
-        {
-        case VIDEO_PALETTE_YUV420P:    wcFormat = PIX_FMT_YUV420P;    break;
-        case VIDEO_PALETTE_YUV422P:    wcFormat = PIX_FMT_YUV422P;    break;
-        case VIDEO_PALETTE_RGB24:      wcFormat = PIX_FMT_BGR24;      break;
-        case VIDEO_PALETTE_RGB32:      wcFormat = PIX_FMT_RGBA32;     break;
-        default:
-            cerr << "Webcam: Unsupported palette mode " << GetPalette() << endl; // Should not get here, caught earlier
-            camClose();
-            return false;
-            break;
-        }
+	SetupMMAP();
 
         StartThread();
     }
     return opened;
 }
 
+void Webcam::SetupMMAP() {
+#ifndef WIN32
+  if ((vCaps.capabilities & V4L2_CAP_READWRITE) || 
+      (!vCaps.capabilities & V4L2_CAP_STREAMING)) {
+    return;
+  }
 
+  struct v4l2_requestbuffers req;
+  memset(&req, 0, sizeof(req));
+  req.count   = WC_MMAP_BUFFERS;
+  req.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  req.memory  = V4L2_MEMORY_MMAP;
+  if (ioctl(hDev, VIDIOC_REQBUFS, &req) != 0) {
+    cerr << "Webcam: VIDIOC_REQBUFS failed" << endl;
+    return;
+  }
+  for (int i = 0; i < WC_MMAP_BUFFERS; i++) {
+    mmapBufDesc[i].index = i;
+    mmapBufDesc[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    mmapBufDesc[i].memory = V4L2_MEMORY_MMAP;
+    if (ioctl(hDev, VIDIOC_QUERYBUF, &mmapBufDesc[i]) != 0) {
+      cerr << "Webcam: VIDIOC_QUERYBUF failed" << endl;
+      return;
+    }
+    mmapBuf[i] = mmap(0, /* start anywhere */
+		      mmapBufDesc[i].length,
+		      PROT_READ,
+		      MAP_SHARED,
+		      hDev,
+		      mmapBufDesc[i].m.offset);
+    if (mmapBuf[i] == MAP_FAILED) {
+      cerr << "Webcam: Unable to mmap buffers" << endl;
+      mmapBuf[i] = NULL;
+      return;
+    }
+  }
+
+  for (int i = 0; i < WC_MMAP_BUFFERS; i++) {
+    if (ioctl(hDev, VIDIOC_QBUF, &mmapBufDesc[i]) != 0) {
+      cerr << "Webcam: failed to initially queue buffers" << endl;
+    }
+  }  
+  
+  int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  if (ioctl(hDev, VIDIOC_STREAMON, &type) != 0) {
+    cerr << "Webcam: Unable to start streaming.  ioctl(VIDIOC_STREAMON) failed" << endl;
+  }
+#endif /* !WIN32 */
+}
+
+void Webcam::ShutdownMMAP() {
+#ifndef WIN32
+  if ((vCaps.capabilities & V4L2_CAP_READWRITE) || 
+      (!vCaps.capabilities & V4L2_CAP_STREAMING)) {
+    return;
+  }
+
+  int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  if (ioctl(hDev, VIDIOC_STREAMOFF, &type) != 0) {
+    cerr << "Webcam: Unable to stop streaming.  ioctl(VIDIOC_STREAMOFF) failed" << endl;
+  }
+  for (int i = 0; i < WC_MMAP_BUFFERS; i++) {
+    if (mmapBuf[i] != NULL) {
+      if (munmap(mmapBuf[i], mmapBufDesc[i].m.offset) != 0) { 
+	cerr << "Webcam: munmap() " << i << " failed" << endl;
+      }
+    }
+    mmapBuf[i] = NULL;
+    memset(&mmapBufDesc[i], 0, sizeof(mmapBufDesc[i]));
+  }
+#endif /* !WIN32 */
+}
+
 void Webcam::camClose()
 {
     KillThread();
 
 #ifndef WIN32
+    
+    ShutdownMMAP();
     if (hDev <= 0)
         cerr << "Can't close a camera that isn't open" << endl;
     else
     {
         // There must be a widget procedure called close so make
         // sure we call the proper one. Screwed me up for ages!
-        ::close(hDev);
-        hDev = 0;
+        if (::close(hDev) != 0) {
+	    cerr << "Unable to close webcam" << endl;
+	}
+	hDev = 0;
     }
+
 #else
     capCaptureStop(hwndCap);
     capPreview(hwndCap, false);
@@ -219,8 +322,17 @@
 
     if (picbuff1)
         delete picbuff1;
+    picbuff1 = NULL;
 
-    picbuff1 = 0;
+    if (workbuff)
+        delete workbuff;
+    workbuff = NULL;
+
+    if (decoder) {
+      decoder->MJPEGStopDecoder();
+      delete decoder;
+    }
+    decoder = NULL;
 }
 
 
@@ -261,9 +373,12 @@
 #ifndef WIN32
     if (hDev > 0)
     {
-        ioctl(hDev, VIDIOCGCAP, &vCaps);
-        ioctl(hDev, VIDIOCGWIN, &vWin);
-        ioctl(hDev, VIDIOCGPICT, &vPic);
+      if (ioctl(hDev, VIDIOC_QUERYCAP, &vCaps) != 0) { 
+	cerr << "Webcam: Error getting webcam capabilities" << endl;
+      }
+      if (ioctl(hDev, VIDIOC_G_FMT, &vFormat) != 0) {
+	cerr << "Webcam: Error getting webcam format" << endl;
+      }
     }
 #else
     capCaptureGetSetup(hwndCap, &capParams, sizeof(capParams));
@@ -276,12 +391,11 @@
 {
     // Note you can't call this whilst the webcam is open because all the buffers will be the wrong size
 #ifndef WIN32
-    memset(&vWin, 0, sizeof(struct video_window));
-    vWin.width = width;
-    vWin.height = height;
+    vFormat.fmt.pix.width = width;
+    vFormat.fmt.pix.height = height;
 
-    if (ioctl(hDev, VIDIOCSWIN, &vWin) == -1)
-        cerr << "Webcam: Error setting capture size " << width << "x" << height << endl;
+    if (ioctl(hDev, VIDIOC_S_FMT, &vFormat) != 0)
+      cerr << "Webcam: Error setting capture size " << width << "x" << height << endl;
 #else
     bitmapInfo.bmiHeader.biHeight = height;
     bitmapInfo.bmiHeader.biWidth = width;
@@ -294,32 +408,32 @@
 
 bool Webcam::SetPalette(unsigned int palette)
 {
+#ifndef WIN32
+    vFormat.fmt.pix.pixelformat = palette;
+    ioctl(hDev, VIDIOC_S_FMT, &vFormat);
+#else
     int depth;
 
     switch(palette)
     {
-    case VIDEO_PALETTE_YUV420P: depth = 12;  break;
-    case VIDEO_PALETTE_YUV422:  depth = 16;  break;
-    case VIDEO_PALETTE_YUV422P: depth = 16;  break;
-    case VIDEO_PALETTE_RGB32:   depth = 32;  break;
-    case VIDEO_PALETTE_RGB24:   depth = 24;  break;
-    default:                    depth = 0;   break;
+    case V4L2_PIX_FMT_YVU420:  depth = 12;  break;
+    case V4L2_PIX_FMT_YUYV:    depth = 16;  break;
+    case V4L2_PIX_FMT_YUV422P: depth = 16;  break;
+    case V4L2_PIX_FMT_BGR32:   depth = 32;  break;
+    case V4L2_PIX_FMT_BGR24:   depth = 24;  break;
+    default:                   depth = 0;   break;
     }
 
-#ifndef WIN32
-    vPic.palette = palette;
-    vPic.depth = depth;
-    ioctl(hDev, VIDIOCSPICT, &vPic);
-#else
     int winPalette = 0;
     switch(palette)
     {
     default:                    
-    case VIDEO_PALETTE_YUV420P: winPalette = (MAKEFOURCC('I', 'Y', 'U', 'V'));   break;
-    case VIDEO_PALETTE_YUV422:  winPalette = (MAKEFOURCC('U', 'Y', 'V', 'Y'));   break;
-    case VIDEO_PALETTE_YUV422P: winPalette = (MAKEFOURCC('Y', 'V', '1', '6'));   break;
-    case VIDEO_PALETTE_RGB32:   winPalette = 0;                                  break;
-    case VIDEO_PALETTE_RGB24:   winPalette = 0;                                  break;
+    case V4L2_PIX_FMT_YVU420:  winPalette = (MAKEFOURCC('I', 'Y', 'U', 'V'));   break;
+    case V4L2_PIX_FMT_YUYV:    winPalette = (MAKEFOURCC('U', 'Y', 'V', 'Y'));   break;
+    case V4L2_PIX_FMT_YUV422P: winPalette = (MAKEFOURCC('Y', 'V', '1', '6'));   break;
+    case V4L2_PIX_FMT_BGR32:   winPalette = 0;                                  break;
+    case V4L2_PIX_FMT_BGR24:   winPalette = 0;                                  break;
+    case V4L2_PIX_FMT_MJPEG:   winPalette = 0;                                  break;
     }
     bitmapInfo.bmiHeader.biCompression = winPalette;
     bitmapInfo.bmiHeader.biBitCount = depth;
@@ -329,7 +443,7 @@
     readCaps();
 
 #ifndef WIN32
-    return (vPic.palette == palette ? true : false);
+    return (vFormat.fmt.pix.pixelformat == palette ? true : false);
 #else
     return ((bitmapInfo.bmiHeader.biCompression == winPalette) && (bitmapInfo.bmiHeader.biBitCount == depth) ? true : false);
 #endif
@@ -339,20 +453,20 @@
 unsigned int Webcam::GetPalette(void) 
 {
 #ifndef WIN32
-    return (vPic.palette);
+    return (vFormat.fmt.pix.pixelformat);
 #else
     int winPalette = 0;
     switch(bitmapInfo.bmiHeader.biCompression)
     {
-    case MAKEFOURCC('I', 'Y', 'U', 'V'):    return VIDEO_PALETTE_YUV420P;
-    case MAKEFOURCC('U', 'Y', 'V', 'Y'):    return VIDEO_PALETTE_YUV422;
-    case MAKEFOURCC('Y', 'V', '1', '6'):    return VIDEO_PALETTE_YUV422P;
+    case MAKEFOURCC('I', 'Y', 'U', 'V'):    return V4L2_PIX_FMT_YVU420;
+    case MAKEFOURCC('U', 'Y', 'V', 'Y'):    return V4L2_PIX_FMT_YUYV;
+    case MAKEFOURCC('Y', 'V', '1', '6'):    return V4L2_PIX_FMT_YUV422P;
     default:                    
     case 0:
         if (bitmapInfo.bmiHeader.biBitCount == 24)
-            return VIDEO_PALETTE_RGB24;
+            return V4L2_PIX_FMT_BGR24;
         else if (bitmapInfo.bmiHeader.biBitCount == 32)
-            return VIDEO_PALETTE_RGB32;
+            return V4L2_PIX_FMT_BGR32;
     }
     return 0;
 #endif
@@ -367,9 +481,10 @@
   {
     if (hDev > 0)
     {
-      vPic.brightness = v;
+      brightness.id = V4L2_CID_BRIGHTNESS;
+      brightness.value = v;
 
-      if (ioctl(hDev, VIDIOCSPICT, &vPic) == -1)
+      if (ioctl(hDev, VIDIOC_S_CTRL, &brightness) == -1)
           cerr << "Error setting brightness" << endl;
 
       readCaps();
@@ -377,7 +492,7 @@
   }
   else
     cerr << "Invalid Brightness parameter" << endl;
-  return vPic.brightness;
+  return brightness.value;
 }
 
 int Webcam::SetContrast(int v)
@@ -386,9 +501,10 @@
   {
     if (hDev > 0)
     {
-      vPic.contrast = v ;
+      contrast.id = V4L2_CID_CONTRAST;
+      contrast.value = v ;
 
-      if (ioctl(hDev, VIDIOCSPICT, &vPic) == -1)
+      if (ioctl(hDev, VIDIOC_S_CTRL, &contrast) == -1)
           cerr << "Error setting contrast" << endl;
 
       readCaps();
@@ -396,7 +512,7 @@
   }
   else
     cerr << "Invalid contrast parameter" << endl;
-  return vPic.contrast;
+  return contrast.value;
 }
 
 
@@ -406,9 +522,10 @@
   {
     if (hDev > 0)
     {
-      vPic.colour = v;
+      colour.id = V4L2_CID_SATURATION;
+      colour.value = v;
 
-      if (ioctl(hDev, VIDIOCSPICT, &vPic) == -1)
+      if (ioctl(hDev, VIDIOC_S_CTRL, &colour) == -1)
           cerr << "Error setting colour" << endl;
 
       readCaps();
@@ -416,7 +533,7 @@
   }
   else
     cerr << "Invalid colour parameter" << endl;
-  return vPic.colour;
+  return colour.value;
 }
 
 
@@ -426,9 +543,10 @@
   {
     if (hDev > 0)
     {
-      vPic.hue = v;
+      hue.id = V4L2_CID_HUE;
+      hue.value = v;
 
-      if (ioctl(hDev, VIDIOCSPICT, &vPic) == -1)
+      if (ioctl(hDev, VIDIOC_S_CTRL, &hue) == -1)
           cerr << "Error setting hue" << endl;
 
       readCaps();
@@ -436,7 +554,7 @@
   }
   else
     cerr << "Invalid hue parameter" << endl;
-  return vPic.hue;
+  return hue.value;
 }
 
 #endif
@@ -463,24 +581,6 @@
   return actualFps;
 }
 
-void Webcam::GetMaxSize(int *x, int *y)
-{
-#ifdef WIN32
-    *y=bitmapInfo.bmiHeader.biHeight; *x=bitmapInfo.bmiHeader.biWidth;
-#else
-    *y=vCaps.maxheight; *x=vCaps.maxwidth; 
-#endif
-};
-
-void Webcam::GetMinSize(int *x, int *y)
-{
-#ifdef WIN32
-    *y=bitmapInfo.bmiHeader.biHeight; *x=bitmapInfo.bmiHeader.biWidth;
-#else
-    *y=vCaps.minheight; *x=vCaps.minwidth; 
-#endif
-};
-
 void Webcam::GetCurSize(int *x, int *y)
 {
     *y = WCHEIGHT; 
@@ -492,7 +592,23 @@
 #ifdef WIN32
     return false;
 #else
-    return ((vCaps.type & VID_TYPE_MONOCHROME) ? true : false); 
+    struct v4l2_fmtdesc fmt;
+    int i = 0;
+    int greyonly = true;
+    while (1) {
+      memset(&fmt, 0, sizeof(fmt));
+      fmt.index = i;
+      fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+      if (ioctl(hDev, VIDIOC_ENUM_FMT, (void *) &fmt) != 0) {
+	return greyonly;
+      }
+      if (fmt.pixelformat != V4L2_PIX_FMT_GREY) {
+	greyonly = false;
+      }
+      i++;
+    }
+    /* never reached */
+    return false;
 #endif
 };
 
@@ -517,15 +633,24 @@
 
     switch (format)
     {
-    case VIDEO_PALETTE_RGB24:   client->frameSize = RGB24_LEN(WCWIDTH, WCHEIGHT);   client->format = PIX_FMT_BGR24;      break;
-    case VIDEO_PALETTE_RGB32:   client->frameSize = RGB32_LEN(WCWIDTH, WCHEIGHT);   client->format = PIX_FMT_RGBA32;     break;
-    case VIDEO_PALETTE_YUV420P: client->frameSize = YUV420P_LEN(WCWIDTH, WCHEIGHT); client->format = PIX_FMT_YUV420P;    break;
-    case VIDEO_PALETTE_YUV422P: client->frameSize = YUV422P_LEN(WCWIDTH, WCHEIGHT); client->format = PIX_FMT_YUV422P;    break;
+    case V4L2_PIX_FMT_BGR24:
+      client->format = PIX_FMT_BGR24;
+      break;
+    case V4L2_PIX_FMT_BGR32:
+      client->format = PIX_FMT_RGBA32;
+      break;
+    case V4L2_PIX_FMT_YVU420:  
+      client->format = PIX_FMT_YUV420P;    
+      break;
+    case V4L2_PIX_FMT_YUV422P: 
+      client->format = PIX_FMT_YUV422P;    
+      break;
     default:
         cerr << "SIP: Attempt to register unsupported Webcam format\n";
         delete client;
         return 0;
     }
+    client->frameSize = avpicture_get_size(client->format, WCWIDTH, WCHEIGHT);
 
     // Create some buffers for the client
     for (int i=0; i<WC_CLIENT_BUFFERS; i++)
@@ -630,6 +755,47 @@
     WebcamThreadWorker();
 }
 
+int Webcam::ReadFrame(unsigned char *outbuf) {
+#ifndef WIN32
+  int len;
+  if ((!(vCaps.capabilities & V4L2_CAP_READWRITE)) &&
+      (!(vCaps.capabilities & V4L2_CAP_STREAMING))) {
+    cerr << "webcam: no supported mechanisms for reading image data" << endl;
+    return -1;
+  }
+
+  memset(outbuf, 0, frameSize);
+
+  if (vCaps.capabilities & V4L2_CAP_READWRITE) {
+    len = read(hDev, outbuf, frameSize);
+    return len;
+  }
+  
+  if (vCaps.capabilities & V4L2_CAP_STREAMING) {
+    v4l2_buffer readBuf;
+    memset(&readBuf, 0, sizeof(readBuf));
+    readBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    readBuf.memory = V4L2_MEMORY_MMAP;
+    if (ioctl(hDev, VIDIOC_DQBUF, &readBuf) != 0) {
+      cerr << "Webcam: Unable to fetch streaming buffer" << endl; 
+      return -1;
+    }
+    len = readBuf.bytesused;
+    if (len > frameSize) { 
+      cerr << "Webcam: outbuf not big enough" << endl;
+      return -1;
+    }
+    memcpy(outbuf, mmapBuf[readBuf.index], len);
+    if (ioctl(hDev, VIDIOC_QBUF, &readBuf) != 0) { 
+      cerr << "Webcam: Unable to requeue buffer" << endl;
+    }
+    return len;
+  }
+
+#endif /* !WIN32 */
+  return -1; 
+}
+
 void Webcam::WebcamThreadWorker()
 {
 #ifndef WIN32
@@ -637,15 +803,31 @@
 
     while((!killWebcamThread) && (hDev > 0))
     {
-        if ((len = read(hDev, picbuff1, frameSize)) == frameSize)
-        {
-            if (killWebcamThread)
-                break;
-                
-            ProcessFrame(picbuff1, frameSize);
-        }
-        else
-            cerr << "Error reading from webcam; got " << len << " bytes; expected " << frameSize << endl;
+      int len = ReadFrame(workbuff);
+
+      /* 
+       * See if any special handling (decompression) is required
+       * for this frame
+       */
+      if (GetPalette() == V4L2_PIX_FMT_MJPEG) {
+	if (!decoder->MJPEGDecodeFrame(workbuff, len, picbuff1, frameSize)) {
+	  cerr << "Unable to decode MJPEG frame" << endl;
+	  len = -1;
+	} else {
+	  len = frameSize;
+	}
+      } else {
+	memcpy(picbuff1, workbuff, frameSize);
+      }
+
+      if (len == frameSize) {
+	if (killWebcamThread)
+	  break;
+	
+	ProcessFrame(picbuff1, frameSize);
+      }
+      else
+	cerr << "Error reading from webcam; got " << len << " bytes; expected " << frameSize << endl;
     }
 #endif
 }
@@ -663,8 +845,20 @@
     if (totalCaptureMs != 0)
         actualFps = (frameCount*1000)/totalCaptureMs;
 
+    int wcFormat = PIX_FMT_NONE;
+    switch(GetPalette())
+      {
+      case V4L2_PIX_FMT_YVU420:     wcFormat = PIX_FMT_YUV420P;       break;
+      case V4L2_PIX_FMT_MJPEG:      wcFormat = decoder->getPixFmt();  break;
+      case V4L2_PIX_FMT_YUV422P:    wcFormat = PIX_FMT_YUV422P;       break;
+      case V4L2_PIX_FMT_BGR24:      wcFormat = PIX_FMT_BGR24;         break;
+      case V4L2_PIX_FMT_BGR32:      wcFormat = PIX_FMT_RGBA32;        break;
+      default:
+	cerr << "Webcam: Unsupported palette mode " << GetPalette() << endl; 
+      }
+	    
     // Check if the webcam needs flipped (some webcams deliver pics upside down)
-    if (wcFlip)
+    if (wcFlip && wcFormat != PIX_FMT_NONE)
     {
         switch(wcFormat)
         {
Index: mjpeg.cpp
===================================================================
--- mjpeg.cpp	(revision 0)
+++ mjpeg.cpp	(revision 0)
@@ -0,0 +1,121 @@
+/*
+	mjpeg.cpp
+
+	(c) 2006 Nick Kralevich
+	
+  Container class for the mjpeg Video Codec, which just interfaces to the libavcodec routines
+
+  TODO:-
+    These are non reentrant so need a mutex implemented, if they are to be used elsewhere in the Myth frontend
+*/
+
+#include <iostream>
+using namespace std;
+
+#ifndef WIN32
+#include "config.h"
+#endif
+
+#include "mjpeg.h"
+
+MJPEGContainer::MJPEGContainer()
+{
+    mjpegDecoder = NULL;
+    mjpegDecContext = NULL;
+    pictureIn = NULL;
+
+    avcodec_init();
+    avcodec_register_all();
+}
+
+MJPEGContainer::~MJPEGContainer()
+{
+}
+
+bool MJPEGContainer::MJPEGStartDecoder(int w, int h)
+{
+    mjpegDecoder = avcodec_find_decoder(CODEC_ID_MJPEG);
+    if (!mjpegDecoder)
+    {
+        cerr << "Could not find MJPEG decoder\n";
+        return false;
+    }
+
+    mjpegDecContext = avcodec_alloc_context();
+    pictureIn = avcodec_alloc_frame();
+
+    mjpegDecContext->codec_id = CODEC_ID_MJPEG;
+    mjpegDecContext->width = w;
+    mjpegDecContext->height = h;
+
+    /* open it */
+    if (avcodec_open(mjpegDecContext, mjpegDecoder) < 0) 
+    {
+        cerr << "Could not open MJPEG Decoder\n";
+        return false;
+    }
+    
+    return true;
+}
+
+int MJPEGContainer::getPixFmt() {
+  return mjpegDecContext->pix_fmt;
+}
+
+uchar *MJPEGContainer::MJPEGDecodeFrame(const uchar *mjpegFrame, int mjpegFrameLen, uchar *outbuf, int outbufSize)
+{
+    int got_picture;
+
+    memset(outbuf, 0, outbufSize);
+
+    int len = avcodec_decode_video(mjpegDecContext, 
+				   pictureIn, 
+				   &got_picture, 
+				   (uint8_t *) mjpegFrame, 
+				   mjpegFrameLen);
+
+    if (!got_picture) {
+      cerr << "Webcam: expected picture but didn't get it..." << endl;
+      return NULL;
+    }
+
+    // int wrap = pictureIn->linesize[0];
+    int xsize = mjpegDecContext->width;
+    int ysize = mjpegDecContext->height;
+    int pic_size = avpicture_get_size(mjpegDecContext->pix_fmt, xsize, ysize);
+    if (pic_size != outbufSize) {
+      cerr << "outbuf size mismatch.  pic_size: " << pic_size << " bufsize: " << outbufSize << endl;
+      return NULL;
+    }
+    
+    int size = avpicture_layout((AVPicture *)pictureIn, 
+				mjpegDecContext->pix_fmt, 
+				xsize, 
+				ysize, 
+				outbuf, 
+				outbufSize);
+    if (size != outbufSize) {
+      cerr << "webcam: avpicture_layout error: " << size << endl;
+      return NULL;
+    }
+    return outbuf;
+}
+
+void MJPEGContainer::MJPEGStopDecoder()
+{
+    int got_picture;
+
+    // See if there is a last frame
+    avcodec_decode_video(mjpegDecContext, pictureIn, &got_picture, NULL, 0);
+
+    if (mjpegDecContext)
+    {
+        avcodec_close(mjpegDecContext);
+        av_free(mjpegDecContext);
+        mjpegDecContext = 0;
+    }
+
+    if (pictureIn)
+        av_free(pictureIn);
+    pictureIn = 0;
+}
Index: h263.cpp
===================================================================
--- h263.cpp	(revision 8629)
+++ h263.cpp	(working copy)
@@ -15,7 +15,6 @@
 using namespace std;
 
 #ifndef WIN32
-#include <linux/videodev.h>
 #include "config.h"
 #endif
 
