From 92f7ddf2f9e63eab1da9f8f134407a5e5b3d7dfa Mon Sep 17 00:00:00 2001
From: Benjamin Pracht <bigben@videolan.org>
Date: Sun, 27 Aug 2006 17:06:30 +0000
Subject: [PATCH] * Some more probing * The debug output from a v4l2 capable
 webcam with this would help...

---
 modules/access/v4l2.c | 180 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 147 insertions(+), 33 deletions(-)

diff --git a/modules/access/v4l2.c b/modules/access/v4l2.c
index 53f36be657d9..81a26c3aae30 100644
--- a/modules/access/v4l2.c
+++ b/modules/access/v4l2.c
@@ -53,6 +53,10 @@ static void Close( vlc_object_t * );
 #define DEV_LONGTEXT N_( \
     "Name of the device to use. " \
     "If you don't specify anything, /dev/video0 will be used.")
+#define INPUT_TEXT N_( "Input" )
+#define INPUT_LONGTEXT N_( \
+    "Input of the card to use (Usually, 0 = tuner, " \
+    "1 = composite, 2 = svideo)." )
 
 
 vlc_module_begin();
@@ -63,6 +67,8 @@ vlc_module_begin();
 
     add_string( "v4l2-dev", "/dev/video0", 0, DEV_TEXT, DEV_LONGTEXT,
                 VLC_FALSE );
+    add_integer( "v4l2-input", 0, NULL, INPUT_TEXT, INPUT_LONGTEXT,
+                VLC_TRUE );
 
     add_shortcut( "v4l2" );
     set_capability( "access_demux", 10 );
@@ -73,10 +79,13 @@ vlc_module_end();
  * Access: local prototypes
  *****************************************************************************/
 
-static int Demux  ( demux_t * );
+static int DemuxMMAP( demux_t * );
 static int Control( demux_t *, int, va_list );
 
-static int OpenDev( demux_t * );
+static int ProbeDev( demux_t * );
+static int OpenVideoDev( demux_t * );
+
+static block_t *GrabVideo( demux_t * );
 
 struct demux_sys_t
 {
@@ -88,6 +97,7 @@ struct demux_sys_t
 
     int i_input;
     struct v4l2_input *p_inputs;
+    int i_selected_input;
 
     int i_audio;
     /* V4L2 devices cannot have more than 32 audio inputs */
@@ -95,6 +105,9 @@ struct demux_sys_t
 
     int i_tuner;
     struct v4l2_tuner *p_tuners;
+
+    int i_codec;
+    struct v4l2_fmtdesc *p_codecs;
 };
 
 /*****************************************************************************
@@ -111,7 +124,6 @@ static int Open( vlc_object_t *p_this )
     demux_sys_t sys;
 
     /* Set up p_demux */
-    p_demux->pf_demux = Demux;
     p_demux->pf_control = Control;
     p_demux->info.i_update = 0;
     p_demux->info.i_title = 0;
@@ -123,7 +135,9 @@ static int Open( vlc_object_t *p_this )
 
     p_sys->psz_device = var_CreateGetString( p_demux, "v4l2-dev" );
 
-    if( OpenDev( p_demux ) < 0 ) return VLC_EGENERIC;
+    if( ProbeDev( p_demux ) < 0 ) return VLC_EGENERIC;
+
+    if( OpenVideoDev( p_demux ) < 0 ) return VLC_EGENERIC;
 
     return VLC_SUCCESS;
 }
@@ -136,8 +150,12 @@ static void Close( vlc_object_t *p_this )
     demux_t     *p_demux = (demux_t *)p_this;
     demux_sys_t *p_sys   = p_demux->p_sys;
 
+    if( p_sys->i_fd_video >= 0 ) close( p_sys->i_fd_video );
+
     if( p_sys->psz_device ) free( p_sys->psz_device );
     if( p_sys->p_inputs ) free( p_sys->p_inputs );
+    if( p_sys->p_tuners ) free( p_sys->p_tuners );
+    if( p_sys->p_codecs ) free( p_sys->p_codecs );
 
     free( p_sys );
 }
@@ -152,17 +170,77 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
 /*****************************************************************************
  * Demux:
  *****************************************************************************/
-static int Demux( demux_t *p_demux )
+static int DemuxMMAP( demux_t *p_demux )
 {
 }
 
 
 /*****************************************************************************
- * OpenDev: open the device and probe for capabilities
+ * OpenVideoDev: open and set up the video device and probe for capabilities
  *****************************************************************************/
-int OpenDev( demux_t *p_demux )
+int OpenVideoDev( demux_t *p_demux )
 {
-    int i_device_index;
+    int i_fd;
+    demux_sys_t *p_sys = p_demux->p_sys;
+
+    if( ( i_fd = open( p_sys->psz_device, O_RDWR ) ) < 0 )
+    {
+        msg_Err( p_demux, "cannot open device (%s)", strerror( errno ) );
+        goto open_failed;
+    }
+
+    p_sys->i_fd_video = i_fd;
+
+    if( p_sys->i_selected_input = var_CreateGetInteger( p_demux, "v4l2-input" )
+        > p_sys->i_input )
+    {
+        msg_Warn( p_demux, "invalid input. Using the default one" );
+        p_sys->i_selected_input = 0;
+    }
+
+    if( ioctl( i_fd, VIDIOC_S_INPUT, &p_sys->i_selected_input ) < 0 )
+    {
+       msg_Err( p_demux, "cannot set input (%s)", strerror( errno ) );
+       goto open_failed;
+    }
+
+    if( p_sys->dev_cap.capabilities & V4L2_CAP_STREAMING )
+    {
+        struct v4l2_requestbuffers reqbuf;
+
+        reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        reqbuf.memory = V4L2_MEMORY_MMAP;
+        reqbuf.count = 0;
+
+        if( ioctl( i_fd, VIDIOC_REQBUFS, &reqbuf ) < 0 )
+        {
+            msg_Err( p_demux, "cannot initiate I/O operation (%s). "
+                    "Only MMAP is supported at the moment", strerror( errno ) );
+            goto open_failed;
+        }
+        p_demux->pf_demux = DemuxMMAP;
+    }
+    else
+    {
+        msg_Warn( p_demux, "I/O method not supported at the moment" );
+        goto open_failed;
+    }
+
+    return VLC_SUCCESS;
+
+open_failed:
+    if( i_fd ) close( i_fd );
+    p_sys->i_fd_video = 0;
+    return VLC_EGENERIC;
+
+}
+
+/*****************************************************************************
+ * ProbeDev: probe for capabilities
+ *****************************************************************************/
+int ProbeDev( demux_t *p_demux )
+{
+    int i_index;
 
     int i_fd;
     demux_sys_t *p_sys = p_demux->p_sys;
@@ -189,14 +267,14 @@ int OpenDev( demux_t *p_demux )
                             p_sys->dev_cap.version & 0xFF,
                             p_sys->dev_cap.bus_info );
 
-    msg_Dbg( p_demux, "The device has the capabilities: (%c) Video Capure, "
+    msg_Dbg( p_demux, "the device has the capabilities: (%c) Video Capure, "
                                                        "(%c) Audio, "
                                                        "(%c) Tuner",
              ( p_sys->dev_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE  ? 'X':' '),
              ( p_sys->dev_cap.capabilities & V4L2_CAP_AUDIO  ? 'X':' '),
              ( p_sys->dev_cap.capabilities & V4L2_CAP_TUNER  ? 'X':' ') );
 
-    msg_Dbg( p_demux, "Supported I/O methods are: (%c) Read/Write, "
+    msg_Dbg( p_demux, "supported I/O methods are: (%c) Read/Write, "
                                                  "(%c) Streaming, "
                                                  "(%c) Asynchronous",
             ( p_sys->dev_cap.capabilities & V4L2_CAP_READWRITE ? 'X':' ' ),
@@ -218,20 +296,20 @@ int OpenDev( demux_t *p_demux )
         if( !p_sys->p_inputs ) goto open_failed;
         memset( p_sys->p_inputs, 0, sizeof( struct v4l2_input ) );
 
-        for( i_device_index = 0; i_device_index < p_sys->i_input; i_device_index++ )
+        for( i_index = 0; i_index < p_sys->i_input; i_index++ )
         {
-            p_sys->p_inputs[i_device_index].index = i_device_index;
+            p_sys->p_inputs[i_index].index = i_index;
 
-            if( ioctl( i_fd, VIDIOC_ENUMINPUT, &p_sys->p_inputs[i_device_index] ) )
+            if( ioctl( i_fd, VIDIOC_ENUMINPUT, &p_sys->p_inputs[i_index] ) )
             {
                 msg_Err( p_demux, "cannot get video input characteristics (%s)",
                                                  strerror( errno ) );
                 goto open_failed;
             }
-            msg_Dbg( p_demux, "Video input %i (%s) has type: %s",
-                                i_device_index,
-                                p_sys->p_inputs[i_device_index].name,
-                                p_sys->p_inputs[i_device_index].type
+            msg_Dbg( p_demux, "video input %i (%s) has type: %s",
+                                i_index,
+                                p_sys->p_inputs[i_index].name,
+                                p_sys->p_inputs[i_index].type
                                         == V4L2_INPUT_TYPE_TUNER ?
                                         "Tuner adapter" :
                                         "External analog input" );
@@ -239,9 +317,9 @@ int OpenDev( demux_t *p_demux )
     }
 
     /* initialize the structures for the ioctls */
-    for( i_device_index = 0; i_device_index < 32; i_device_index++ )
+    for( i_index = 0; i_index < 32; i_index++ )
     {
-        p_sys->p_audios[i_device_index].index = i_device_index;
+        p_sys->p_audios[i_index].index = i_index;
     }
 
     /* Probe audio inputs */
@@ -258,7 +336,7 @@ int OpenDev( demux_t *p_demux )
                 goto open_failed;
             }
 
-            msg_Dbg( p_demux, "Audio device %i (%s) is %s",
+            msg_Dbg( p_demux, "audio device %i (%s) is %s",
                                 p_sys->i_audio,
                                 p_sys->p_audios[p_sys->i_audio].name,
                                 p_sys->p_audios[p_sys->i_audio].capability &
@@ -271,8 +349,7 @@ int OpenDev( demux_t *p_demux )
 
     if( p_sys->dev_cap.capabilities & V4L2_CAP_TUNER )
     {
-        struct v4l2_tuner tuner;
-        memset( &tuner, 0, sizeof( struct v4l2_tuner ) );
+        struct v4l2_tuner tuner = {};
 
         while( ioctl( i_fd, VIDIOC_S_TUNER, &tuner ) >= 0 )
         {
@@ -284,34 +361,71 @@ int OpenDev( demux_t *p_demux )
         if( !p_sys->p_tuners ) goto open_failed;
         memset( p_sys->p_tuners, 0, sizeof( struct v4l2_tuner ) );
 
-        for( i_device_index = 0; i_device_index < p_sys->i_tuner; i_device_index++ )
+        for( i_index = 0; i_index < p_sys->i_tuner; i_index++ )
         {
-            p_sys->p_tuners[i_device_index].index = i_device_index;
+            p_sys->p_tuners[i_index].index = i_index;
 
-            if( ioctl( i_fd, VIDIOC_G_TUNER, &p_sys->p_tuners[i_device_index] ) )
+            if( ioctl( i_fd, VIDIOC_G_TUNER, &p_sys->p_tuners[i_index] ) )
             {
                 msg_Err( p_demux, "cannot get tuner characteristics (%s)",
                                                  strerror( errno ) );
                 goto open_failed;
             }
-            msg_Dbg( p_demux, "Tuner %i (%s) has type: %s, "
+            msg_Dbg( p_demux, "tuner %i (%s) has type: %s, "
                               "frequency range: %.1f %s -> %.1f %s",
-                                i_device_index,
-                                p_sys->p_tuners[i_device_index].name,
-                                p_sys->p_tuners[i_device_index].type
+                                i_index,
+                                p_sys->p_tuners[i_index].name,
+                                p_sys->p_tuners[i_index].type
                                         == V4L2_TUNER_RADIO ?
                                         "Radio" : "Analog TV",
-                                p_sys->p_tuners[i_device_index].rangelow * 62.5,
-                                p_sys->p_tuners[i_device_index].capability &
+                                p_sys->p_tuners[i_index].rangelow * 62.5,
+                                p_sys->p_tuners[i_index].capability &
                                         V4L2_TUNER_CAP_LOW ?
                                         "Hz" : "kHz",
-                                p_sys->p_tuners[i_device_index].rangehigh * 62.5,
-                                p_sys->p_tuners[i_device_index].capability &
+                                p_sys->p_tuners[i_index].rangehigh * 62.5,
+                                p_sys->p_tuners[i_index].capability &
                                         V4L2_TUNER_CAP_LOW ?
                                         "Hz" : "kHz" );
         }
     }
 
+    /* Probe for available chromas */
+    if( p_sys->dev_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE )
+    {
+        struct v4l2_fmtdesc codec = {};
+
+        i_index = 0;
+        codec.index = i_index;
+        codec.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+        while( ioctl( i_fd, VIDIOC_ENUM_FMT, &codec ) >= 0 )
+        {
+            i_index++;
+            codec.index = i_index;
+        }
+
+        p_sys->i_codec = i_index;
+
+        p_sys->p_codecs = malloc( p_sys->i_codec * sizeof( struct v4l2_fmtdesc ) );
+        memset( p_sys->p_codecs, 0, p_sys->i_codec * sizeof( struct v4l2_fmtdesc ) ); 
+
+        for( i_index = 0; i_index < p_sys->i_codec; i_index++ )
+        {
+            p_sys->p_codecs[i_index].index = i_index;
+            p_sys->p_codecs[i_index].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+            if( ioctl( i_fd, VIDIOC_ENUM_FMT, &p_sys->p_codecs[i_index] ) < 0 )
+            {
+                msg_Err( p_demux, "cannot get codec description (%s)", strerror( errno ) );
+                goto open_failed;
+            }
+
+            msg_Dbg( p_demux, "device supports Codec %s",
+                                p_sys->p_codecs[i_index].description );
+        }
+    }
+
+
     if( i_fd >= 0 ) close( i_fd );
     return VLC_SUCCESS;
 
-- 
GitLab