Index: trunk/MagicSoft/Cosy/videodev/MVideo.cc
===================================================================
--- trunk/MagicSoft/Cosy/videodev/MVideo.cc	(revision 8860)
+++ trunk/MagicSoft/Cosy/videodev/MVideo.cc	(revision 8861)
@@ -45,4 +45,5 @@
 #include <sys/ioctl.h> // ioctl
 
+#include <TEnv.h>
 #include <TString.h>
 
@@ -50,8 +51,20 @@
 #include "MLogManip.h"
 
+#undef DEBUG
+
 using namespace std;
 
 //ClassImp(MVideo);
 
+MVideoCtrl::MVideoCtrl(const v4l2_queryctrl &ctrl)
+{
+    fId      = ctrl.id;
+    fName    = (const char*)ctrl.name;
+    fMinimum = ctrl.minimum;
+    fMaximum = ctrl.maximum;
+    fStep    = ctrl.step;
+    fDefault = ctrl.default_value;
+}
+
 // -------------------------------------------------------------
 //
@@ -61,4 +74,6 @@
 {
     Reset();
+
+    fControls.SetOwner();
 }
 
@@ -72,8 +87,12 @@
     memset(&fChannel, 0, sizeof(fChannel));
     memset(&fBuffer,  0, sizeof(fBuffer));
+    memset(&fAbil,    0, sizeof(fAbil));
 
     fFileDesc = -1;
     fMapBuffer = 0;
     fChannel.channel = -1;
+    fAbil.tuner = -1;
+
+    fControls.Delete();
 }
 
@@ -137,4 +156,178 @@
 // -------------------------------------------------------------
 //
+// Read the video standard
+//
+Bool_t MVideo::GetVideoStandard()
+{
+    return Ioctl(VIDIOC_G_STD, &fVideoStandard)==-1;
+}
+
+// -------------------------------------------------------------
+//
+// Read the abilities of the tuner
+//
+Bool_t MVideo::GetTunerAbilities()
+{
+    fAbil.tuner = 0; // FIXME?
+    return Ioctl(VIDIOCGTUNER, &fAbil)!=-1;
+}
+
+// -------------------------------------------------------------
+//
+// Enumerate (get) all controls from the device and store them
+// as MVideoCtrl in fControls, starting with the id given as
+// argument.
+//
+Bool_t MVideo::EnumerateControls(UInt_t id)
+{
+    struct v4l2_queryctrl qctrl;
+    qctrl.id = id;
+
+    while (1)
+    {
+        if (Ioctl (VIDIOC_QUERYCTRL, &qctrl)==-1)
+            break;
+
+        if (qctrl.maximum<=qctrl.minimum)
+            continue;
+
+        fControls.Add(new MVideoCtrl(qctrl));
+
+        qctrl.id++;
+    }
+
+    return kTRUE;
+}
+
+// -------------------------------------------------------------
+//
+// Enumerate (get) all basic and private controls from the
+// device and store them as MVideoCtrl in fControls.
+//
+Bool_t MVideo::EnumerateControls()
+{
+    if (!EnumerateControls(V4L2_CID_BASE))
+        return kFALSE;
+    if (!EnumerateControls(V4L2_CID_PRIVATE_BASE))
+        return kFALSE;
+
+    return kTRUE;
+}
+
+// -------------------------------------------------------------
+//
+// Reset a given control to it's default value as defined
+// by the device.
+//
+Bool_t MVideo::ResetControl(MVideoCtrl &vctrl) const
+{
+    return WriteControl(vctrl, vctrl.fDefault);
+}
+
+// -------------------------------------------------------------
+//
+// Reset all enumereated device controls to their default.
+// The default is defined by the device iteself.
+//
+Bool_t MVideo::ResetControls() const
+{
+    Bool_t rc = kTRUE;
+
+    TIter Next(&fControls);
+    MVideoCtrl *ctrl = 0;
+    while ((ctrl=((MVideoCtrl*)Next())))
+        if (!ResetControl(*ctrl))
+        {
+            gLog << err << "ERROR - Could not reset " << ctrl->fName << "." << endl;
+            rc = kFALSE;
+        }
+
+    return rc;
+}
+
+// -------------------------------------------------------------
+//
+//  Read the value of the given control from the device
+// and store it back into the given MVideoCtrl.
+//
+Bool_t MVideo::ReadControl(MVideoCtrl &vctrl) const
+{
+    struct v4l2_control ctrl = { vctrl.fId, 0 };
+    if (Ioctl(VIDIOC_G_CTRL, &ctrl)==-1)
+        return kFALSE;
+
+    vctrl.fValue = ctrl.value;
+
+    return kTRUE;
+}
+
+// -------------------------------------------------------------
+//
+// Write the given value into the given control of the device.
+// On success the value is stored in the given MVideoCtrl.
+//
+Bool_t MVideo::WriteControl(MVideoCtrl &vctrl, Int_t val) const
+{
+    if (val<vctrl.fMinimum)
+    {
+        gLog << err << "ERROR - Value of " << val << " below minimum of " << vctrl.fMinimum << " for " << vctrl.fName << endl;
+        return kFALSE;
+    }
+
+    if (val>vctrl.fMaximum)
+    {
+        gLog << err << "ERROR - Value of " << val << " above maximum of " << vctrl.fMaximum << " for " << vctrl.fName << endl;
+        return kFALSE;
+    }
+
+    struct v4l2_control ctrl = { vctrl.fId, val };
+    if (Ioctl(VIDIOC_S_CTRL, &ctrl)==-1)
+        return kFALSE;
+
+    vctrl.fValue = val;
+
+    return kTRUE;
+}
+
+// -------------------------------------------------------------
+//
+// Set all controls from a TEnv. Note that all whitespaces
+// and colons in the control names (as defined by the name of
+// the MVideoCtrls stored in fControls) are replaced by
+// underscores.
+//
+Bool_t MVideo::SetControls(TEnv &env) const
+{
+    Bool_t rc = kTRUE;
+
+    TIter Next(&fControls);
+    TObject *o = 0;
+    while ((o=Next()))
+    {
+        if (!env.Defined(o->GetName()))
+            continue;
+
+        TString str = env.GetValue(o->GetName(), "");
+        str = str.Strip(TString::kBoth);
+        str.ReplaceAll(" ", "_");
+        str.ReplaceAll(":", "_");
+        if (str.IsNull())
+            continue;
+
+        MVideoCtrl &ctrl = *static_cast<MVideoCtrl*>(o);
+
+        const Int_t val = str=="default" || str=="def" ?
+            ctrl.fDefault : env.GetValue(o->GetName(), 0);
+
+        if (!WriteControl(ctrl, val))
+            rc = kFALSE;
+    }
+
+    return rc;
+}
+
+
+// -------------------------------------------------------------
+//
 // Open channel ch of the device
 //
@@ -184,4 +377,25 @@
     }
 
+    gLog << warn << "Setting video standard to PAL-N." << endl;
+
+    fVideoStandard = V4L2_STD_PAL_N;
+    if (Ioctl(VIDIOC_S_STD, &fVideoStandard)==-1)
+    {
+        gLog << err << "ERROR - Could not set video standard to PAL-N." << endl;
+        return kFALSE;
+    }
+
+    if (!EnumerateControls())
+    {
+        gLog << err << "ERROR - Could not enumerate controls." << endl;
+        return kFALSE;
+    }
+
+    if (!ResetControls())
+    {
+        gLog << err << "ERROR - Could not reset controls to default." << endl;
+        return kFALSE;
+    }
+
     if (!GetCapabilities())
     {
@@ -198,5 +412,14 @@
         return kFALSE;
     }
-
+/*
+    if (HasTuner())
+    {
+        if (!GetTunerAbilities())
+        {
+            gLog << err << "ERROR - Couldn't get tuner abilities." << endl;
+            return kFALSE;
+        }
+    }
+ */
     // get mmap grab buffer info
     if (Ioctl(VIDIOCGMBUF, &fBuffer)==-1)
@@ -207,5 +430,5 @@
 
     // map file (device) into memory
-    fMapBuffer = (char*)mmap(0, fBuffer.size, PROT_READ|PROT_WRITE, MAP_SHARED, fFileDesc, 0);
+    fMapBuffer = (unsigned char*)mmap(0, fBuffer.size, PROT_READ|PROT_WRITE, MAP_SHARED, fFileDesc, 0);
     if (fMapBuffer == (void*)-1)
     {
@@ -258,10 +481,16 @@
 Bool_t MVideo::CaptureStart(unsigned int frame) const
 {
+    frame %= fBuffer.frames;
+
     struct video_mmap gb =
     {
-        frame%fBuffer.frames,            // frame
+        frame,                           // frame
         fCaps.maxheight, fCaps.maxwidth, // height, width
-        VIDEO_PALETTE_RGB24              // palette
+        VIDEO_PALETTE_RGB24             // palette
     };
+
+#ifdef DEBUG
+    gLog << dbg << "CapturStart(" << frame << ")" << endl;
+#endif
 
     //
@@ -273,5 +502,5 @@
 //    if (errno == EAGAIN)
     gLog << err;
-    gLog << "ERROR - Couldn't start capturing frame " << frame << " - unable to sync." << endl;
+    gLog << "ERROR - Couldn't start capturing frame " << frame << "." << endl;
     gLog << "        Maybe your card doesn't support VIDEO_PALETTE_RGB24." << endl;
 
@@ -283,11 +512,16 @@
 // Wait until hardware has finished capture into framebuffer frame
 //
-Int_t MVideo::CaptureWait(unsigned int frame, char **ptr) const
+Int_t MVideo::CaptureWait(unsigned int frame, unsigned char **ptr) const
 {
     frame %= fBuffer.frames;
 
-    *ptr = NULL;
+    if (ptr)
+        *ptr = NULL;
 
     const int SYNC_TIMEOUT = 1;
+
+#ifdef DEBUG
+    gLog << dbg << "CaptureWait(" << frame << ")" << endl;
+#endif
 
     alarm(SYNC_TIMEOUT);
@@ -302,9 +536,10 @@
     if (rc==-1)
     {
-        gLog << err << "ERROR - Waiting for captured frame failed." << endl;
-        return kFALSE;
-    }
-
-    *ptr = fMapBuffer+fBuffer.offsets[frame];
+        gLog << err << "ERROR - Waiting for " << frame << " frame failed." << endl;
+        return kFALSE;
+    }
+
+    if (ptr)
+        *ptr = fMapBuffer+fBuffer.offsets[frame];
 
     return kTRUE;
@@ -315,8 +550,8 @@
 // Change the channel of a priviously opened device
 //
-Bool_t MVideo::SetChannel(Int_t chan)
+Int_t MVideo::SetChannel(Int_t chan)
 {
     if (fChannel.channel==chan)
-        return kTRUE;
+        return kSKIP;
 
     if (chan<0 || chan>=fCaps.channels)
@@ -360,4 +595,13 @@
 // -------------------------------------------------------------
 //
+// Has a tuner
+//
+Bool_t MVideo::HasTuner() const
+{
+    return fCaps.type&VID_TYPE_TUNER;
+}
+
+// -------------------------------------------------------------
+//
 // Returns the number of frame buffers which can be used
 //
@@ -394,5 +638,5 @@
     if (CanCapture())
         rc += " capture";
-    if (type&VID_TYPE_TUNER)
+    if (HasTuner())
         rc += " tuner";
     if (type&VID_TYPE_TELETEXT)
@@ -415,4 +659,38 @@
 }
 
+TString MVideo::GetTunerFlags(Int_t flags) const
+{
+    TString rc;
+    if (flags&VIDEO_TUNER_PAL)
+        rc += " PAL";
+    if (flags&VIDEO_TUNER_NTSC)
+        rc += " NTSC";
+    if (flags&VIDEO_TUNER_SECAM)
+        rc += " SECAM";
+    if (flags&VIDEO_TUNER_LOW)
+        rc += " kHz";
+    if (flags&VIDEO_TUNER_NORM)
+        rc += " CanSetNorm";
+    if (flags&VIDEO_TUNER_STEREO_ON)
+        rc += " StereoOn";
+    return rc;
+}
+
+TString MVideo::GetTunerMode(Int_t mode) const
+{
+    switch (mode)
+    {
+    case VIDEO_MODE_PAL:
+        return "PAL";
+    case VIDEO_MODE_NTSC:
+        return "NTSC";
+    case VIDEO_MODE_SECAM:
+        return "SECAM";
+    case VIDEO_MODE_AUTO:
+        return "AUTO";
+    }
+    return "undefined";
+}
+
 // -------------------------------------------------------------
 //
@@ -426,4 +704,6 @@
     if (flags&VIDEO_VC_AUDIO)
         rc += " audio";
+//    if (flags&VIDEO_VC_NORM)
+//        rc += " normsetting";
     return rc;
 }
@@ -438,5 +718,5 @@
         return "TV";
     if (type&VIDEO_TYPE_CAMERA)
-        return "camera";
+        return "Camera";
     return "unknown";
 }
@@ -448,33 +728,35 @@
 TString MVideo::GetPalette(Int_t pal) const
 {
-    if (pal&VIDEO_PALETTE_GREY)
-        return "Linear intensity grey scale";
-    if (pal&VIDEO_PALETTE_HI240)
-        return "BT848 8-bit color cube";
-    if (pal&VIDEO_PALETTE_RGB565)
-        return "RGB565 packed into 16-bit words";
-    if (pal&VIDEO_PALETTE_RGB555)
-        return "RGB555 packed into 16-bit words, top bit undefined";
-    if (pal&VIDEO_PALETTE_RGB24)
-        return "RGB888 packed into 24-bit words";
-    if (pal&VIDEO_PALETTE_RGB32)
-        return "RGB888 packed into the low three bytes of 32-bit words. Top bits undefined.";
-    if (pal&VIDEO_PALETTE_YUV422)
-        return "Video style YUV422 - 8-bit packed, 4-bit Y, 2-bits U, 2-bits V";
-    if (pal&VIDEO_PALETTE_YUYV)
-        return "YUYV";
-    if (pal&VIDEO_PALETTE_UYVY)
-        return "UYVY";
-    if (pal&VIDEO_PALETTE_YUV420)
-        return "YUV420";
-    if (pal&VIDEO_PALETTE_YUV411)
-        return "YUV411";
-    if (pal&VIDEO_PALETTE_RAW)
-        return "Raw capture (Bt848)";
-    if (pal&VIDEO_PALETTE_YUV422P)
-        return "YUV 4:2:2 planar";
-    if (pal&VIDEO_PALETTE_YUV411P)
-        return "YUV 4:1:1 planar";
-
+    switch (pal)
+    {
+    case VIDEO_PALETTE_GREY:
+        return "VIDEO_PALETTE_GREY: Linear intensity grey scale";
+    case VIDEO_PALETTE_HI240:
+        return "VIDEO_PALETTE_HI240: BT848 8-bit color cube";
+    case VIDEO_PALETTE_RGB565:
+        return "VIDEO_PALETTE_RGB565: RGB565 packed into 16-bit words";
+    case VIDEO_PALETTE_RGB555:
+        return "VIDEO_PALETTE_RGB555: RGB555 packed into 16-bit words, top bit undefined";
+    case VIDEO_PALETTE_RGB24:
+        return "VIDEO_PALETTE_RGB24: RGB888 packed into 24-bit words";
+    case VIDEO_PALETTE_RGB32:
+        return "VIDEO_PALETTE_RGB32: RGB888 packed into the low three bytes of 32-bit words. Top bits undefined.";
+    case VIDEO_PALETTE_YUV422:
+        return "VIDEO_PALETTE_YUV422: Video style YUV422 - 8-bit packed, 4-bit Y, 2-bits U, 2-bits V";
+    case VIDEO_PALETTE_YUYV:
+        return "VIDEO_PALETTE_YUYV: YUYV";
+    case VIDEO_PALETTE_UYVY:
+        return "VIDEO_PALETTE_UYVY: UYVY";
+    case VIDEO_PALETTE_YUV420:
+        return "VIDEO_PALETTE_YUV420: YUV420";
+    case VIDEO_PALETTE_YUV411:
+        return "VIDEO_PALETTE_YUV411: YUV411";
+    case VIDEO_PALETTE_RAW:
+        return "VIDEO_PALETTE_RAW: Raw capture (Bt848)";
+    case VIDEO_PALETTE_YUV422P:
+        return "VIDEO_PALETTE_YUV422P: YUV 4:2:2 planar";
+    case VIDEO_PALETTE_YUV411P:
+        return "VIDEO_PALETTE_YUV411P: YUV 4:1:1 planar";
+    }
     return "unknown";
 }
@@ -505,9 +787,20 @@
     {
         gLog  << " - Channel:    " << fChannel.channel << " (" << fChannel.name << ")" << endl;
-        gLog  << " - IsA:        " << GetChannelType(fChannel.type) << " with " << GetChannelFlags(fChannel.flags) << endl;
+        gLog  << " - IsA:        " << GetChannelType(fChannel.type) << " with " << GetChannelFlags(fChannel.flags) << " (" << fChannel.flags << ")" << endl;
         //if (fChannel.flags&VIDEO_VC_NORM)
         gLog  << " - Norm:       " << fChannel.norm << endl;
         gLog  << endl;
     }
+
+    if (fAbil.tuner>=0)
+    {
+        gLog << " - Tuner:           " << fAbil.tuner << endl;
+        gLog << " - Name:            " << fAbil.name << endl;
+        gLog << " - Tuner Range:     " << fAbil.rangelow << " - " << fAbil.rangehigh << endl;
+        gLog << " - Tuner flags:    " << GetTunerFlags(fAbil.flags) << " (" << fAbil.flags << ")" << endl;
+        gLog << " - Tuner mode:      " << GetTunerMode(fAbil.mode) << " (" << fAbil.mode << ")" <<endl;
+        gLog << " - Signal Strength: " << fAbil.signal << endl;
+    }
+
     gLog  << " - Brightness: " << fProp.brightness << endl;
     gLog  << " - Hue:        " << fProp.hue << endl;
@@ -524,4 +817,7 @@
         gLog  << " 0x" << fBuffer.offsets[i];
     gLog  << dec << endl;
+
+    gLog << "Controls:" << endl;
+    fControls.Print();
 }
 
Index: trunk/MagicSoft/Cosy/videodev/MVideo.h
===================================================================
--- trunk/MagicSoft/Cosy/videodev/MVideo.h	(revision 8860)
+++ trunk/MagicSoft/Cosy/videodev/MVideo.h	(revision 8861)
@@ -8,7 +8,36 @@
 #ifndef __CINT__
 #ifndef __LINUX_VIDEODEV_H
-#include "videodev.h" // video4linux
+#include <linux/videodev.h>  // video4linux
+#endif
+#ifndef __LINUX_VIDEODEV2_H
+#include <linux/videodev2.h> // video4linux2
 #endif
 #endif
+
+struct v4l2_queryctrl;
+class TEnv;
+
+class MVideoCtrl : public TObject
+{
+    friend class MVideo;
+private:
+    UInt_t  fId;
+    //enum v4l2_ctrl_type  type;
+    TString fName;
+    Int_t   fMinimum;
+    Int_t   fMaximum;
+    Int_t   fStep;
+    Int_t   fDefault;
+    UInt_t  fFlags;
+
+    UInt_t  fValue;
+
+public:
+    MVideoCtrl(const v4l2_queryctrl &ctrl);
+    const char *GetName() const { return fName; }
+    const char *GetTitle() const { return Form("Range=[%d;%d] Step=%d Def=%d", fMinimum, fMaximum, fStep, fDefault); }
+
+    //ClassDef(MVideoCtrl, 0) // Helper class to enumare device controls
+};
 
 class MVideo
@@ -19,5 +48,5 @@
     int fFileDesc; // File descriptor
 
-    char *fMapBuffer;
+    unsigned char *fMapBuffer;
 
 protected:
@@ -26,4 +55,9 @@
     struct video_mbuf       fBuffer;    // Buffer information
     struct video_picture    fProp;      // Picture properties
+    struct video_tuner      fAbil;      // Tuner abilities
+
+    ULong64_t fVideoStandard;
+
+    TList fControls;
 
 private:
@@ -32,6 +66,10 @@
     void Reset();
 
+    Bool_t EnumerateControls(UInt_t id);
+    Bool_t EnumerateControls();
     Bool_t GetCapabilities();
     Bool_t GetProperties();
+    Bool_t GetTunerAbilities();
+    Bool_t GetVideoStandard();
     Bool_t Init(Int_t channel);
 
@@ -40,4 +78,6 @@
     TString GetChannelFlags(Int_t flags) const;
     TString GetChannelType(Int_t type) const;
+    TString GetTunerFlags(Int_t type) const;
+    TString GetTunerMode(Int_t type) const;
     TString GetPalette(Int_t pal) const;
 
@@ -49,4 +89,5 @@
     Bool_t IsOpen() const { return fFileDesc>0 && fMapBuffer; }
     Bool_t CanCapture() const;
+    Bool_t HasTuner() const;
     Int_t  GetNumBuffers() const;
 
@@ -58,9 +99,14 @@
     Int_t  Close();
 
-    Bool_t SetChannel(Int_t chan);
+    Int_t SetChannel(Int_t chan);
+    Bool_t ReadControl(MVideoCtrl &vctrl) const;
+    Bool_t WriteControl(MVideoCtrl &vctrl, Int_t val) const;
+    Bool_t SetControls(TEnv &env) const;
+    Bool_t ResetControl(MVideoCtrl &vctrl) const;
+    Bool_t ResetControls() const;
 
     // Image capture
     Bool_t CaptureStart(unsigned int frame) const;
-    Int_t  CaptureWait(unsigned int frame, char **ptr) const;
+    Int_t  CaptureWait(unsigned int frame, unsigned char **ptr=0) const;
 
     // Support
