From b8a181f54b478a4d5fbdadf32f9cf49728949bd7 Mon Sep 17 00:00:00 2001
From: basos g <noxelia 4t gmail d0t c0m>
Date: Tue, 31 Mar 2009 15:16:21 +0000
Subject: [PATCH 20/20] ADD Dshow Analog Video Device Standart Selection

Added a new string list configuration option to adjust the
analog video standart (PALX, NTSCX, ... ) on analog devices.
It is a dynamic list that is populated after reading the
capabilites of the corresponding device
---
 configure.ac                   |    2 +-
 modules/access/dshow/dshow.cpp |  219 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 213 insertions(+), 8 deletions(-)

diff --git a/configure.ac b/configure.ac
index 1b4a5fd..3e3382c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2223,7 +2223,7 @@ then
       AC_CHECK_HEADERS(dshow.h,
       [ VLC_ADD_PLUGIN([dshow])
         VLC_ADD_CXXFLAGS([dshow],[])
-        VLC_ADD_LIBS([dshow],[-lole32 -loleaut32 -luuid -lstrmiids]) ])
+        VLC_ADD_LIBS([dshow],[-lstrmiids -lole32 -loleaut32 -luuid]) ])
     AC_LANG_POP(C++)
   fi
 fi
diff --git a/modules/access/dshow/dshow.cpp b/modules/access/dshow/dshow.cpp
index 68086f1..3d216b4 100644
--- a/modules/access/dshow/dshow.cpp
+++ b/modules/access/dshow/dshow.cpp
@@ -66,6 +66,8 @@ static int FindDevicesCallback( vlc_object_t *, char const *,
                                 vlc_value_t, vlc_value_t, void * );
 static int ConfigDevicesCallback( vlc_object_t *, char const *,
                                   vlc_value_t, vlc_value_t, void * );
+static int UpdateVideoStdsCallback( vlc_object_t *, char const *,
+                                  vlc_value_t, vlc_value_t, void * );
 
 static void ShowPropertyPage( IUnknown * );
 static void ShowDeviceProperties( vlc_object_t *, ICaptureGraphBuilder2 *,
@@ -95,6 +97,8 @@ static const char *const ppsz_amtuner_mode_text[] = { N_("Default"),
                                           N_("FM radio"),
                                           N_("AM radio"),
                                           N_("DSS") };
+static const char *const ppsz_vstd[] = { "None" };
+static const char *const ppsz_vdev_slaves[] = { "dshow-vstd" };
 
 #define CACHING_TEXT N_("Caching value in ms")
 #define CACHING_LONGTEXT N_( \
@@ -123,6 +127,9 @@ static const char *const ppsz_amtuner_mode_text[] = { N_("Default"),
 #define FPS_LONGTEXT N_( \
     "Force the DirectShow video input to use a specific frame rate" \
     "(eg. 0 means default, 25, 29.97, 50, 59.94, etc.)")
+#define VSTD_TEXT N_("Analog Video Standart")
+#define VSTD_LONGTEXT N_( \
+    "Define the video standart used to interpret analog signal (on supported devices)")
 #define CONFIG_TEXT N_("Device properties")
 #define CONFIG_LONGTEXT N_( \
     "Show the properties dialog of the selected device before starting the " \
@@ -183,6 +190,7 @@ static void AccessClose( vlc_object_t * );
 static int  DemuxOpen  ( vlc_object_t * );
 static void DemuxClose ( vlc_object_t * );
 
+
 vlc_module_begin ()
     set_shortname( N_("DirectShow") )
     set_description( N_("DirectShow input") )
@@ -195,6 +203,7 @@ vlc_module_begin ()
         change_string_list( ppsz_vdev, ppsz_vdev_text, FindDevicesCallback )
         change_action_add( FindDevicesCallback, N_("Refresh list") )
         change_action_add( ConfigDevicesCallback, N_("Configure") )
+        change_slave_list( ppsz_vdev_slaves )
 
     add_string( "dshow-adev", NULL, NULL, ADEV_TEXT, ADEV_LONGTEXT, false)
         change_string_list( ppsz_adev, ppsz_adev_text, FindDevicesCallback )
@@ -205,6 +214,9 @@ vlc_module_begin ()
 
     add_string( "dshow-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true )
 
+    add_string( "dshow-vstd", NULL, NULL, VSTD_TEXT, VSTD_LONGTEXT, true )
+        change_string_list( ppsz_vstd, NULL, UpdateVideoStdsCallback )
+
     add_float( "dshow-fps", 0.0f, NULL, FPS_TEXT, FPS_LONGTEXT, true )
 
     add_bool( "dshow-config", false, NULL, CONFIG_TEXT, CONFIG_LONGTEXT, true )
@@ -280,6 +292,56 @@ typedef struct dshow_stream_t
     deque<VLCMediaSample> samples_queue;
 } dshow_stream_t;
 
+struct analog_video_std_mapping_t
+{
+    const char*   psz_string ;
+    LONG    lCode ;
+} analog_video_std_mappings[] =
+{
+    { "None",        0x00000000 },
+    { "NTSC_M",      0x00000001 },
+    { "NTSC_M_J",    0x00000002 },
+    { "NTSC_433",    0x00000004 },
+    { "PAL_B",       0x00000010 },
+    { "PAL_D",       0x00000020 },
+    { "PAL_H",       0x00000080 },
+    { "PAL_I",       0x00000100 },
+    { "PAL_M",       0x00000200 },
+    { "PAL_N",       0x00000400 },
+    { "PAL_60",      0x00000800 },
+    { "SECAM_B",     0x00001000 },
+    { "SECAM_D",     0x00002000 },
+    { "SECAM_G",     0x00004000 },
+    { "SECAM_H",     0x00008000 },
+    { "SECAM_K",     0x00010000 },
+    { "SECAM_K1",    0x00020000 },
+    { "SECAM_L",     0x00040000 },
+    { "SECAM_L1",    0x00080000 },
+    { "PAL_N_COMBO", 0x00100000 }
+} ;
+
+static const char* AnalogVideoStd_GetNextString( LONG *plCodeMask )
+{
+    for ( int i = 1; i < sizeof( analog_video_std_mappings ) / sizeof( struct analog_video_std_mapping_t ) ; i++ )
+        if ( *plCodeMask & analog_video_std_mappings[i].lCode ==  analog_video_std_mappings[i].lCode )
+        {
+            /* mask out found code */
+            *plCodeMask = *plCodeMask & ~analog_video_std_mappings[i].lCode ;
+            return analog_video_std_mappings[i].psz_string ;
+        }
+    return NULL ;
+}
+
+static LONG AnalogVideoStd_GetCode( const char* psz_string )
+{
+    for ( int i = 0; i < sizeof( analog_video_std_mappings ) / sizeof( struct analog_video_std_mapping_t ) ; i++ )
+        if ( !strcasecmp( psz_string, analog_video_std_mappings[i].psz_string ) )
+        {
+            return analog_video_std_mappings[i].lCode ;
+        }
+    return -1L ;
+}
+
 /*****************************************************************************
  * DirectShow utility functions
  *****************************************************************************/
@@ -427,6 +489,7 @@ static int CommonOpen( vlc_object_t *p_this, access_sys_t *p_sys,
     free( val.psz_string );
 
     var_Create( p_this, "dshow-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
+    var_Create( p_this, "dshow-vstd", VLC_VAR_STRING | VLC_VAR_DOINHERIT ) ;
     var_Create( p_this, "dshow-tuner-channel",
                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
     var_Create( p_this, "dshow-tuner-country",
@@ -993,6 +1056,40 @@ static int OpenDevice( vlc_object_t *p_this, access_sys_t *p_sys,
 
     AM_MEDIA_TYPE *mt = NULL;
 
+    if ( !b_audio )
+    {
+        /* Set the AnalogVideo Standard ( if present and if applicable ) */
+        char* psz_vstd =
+            var_GetString( p_this, "dshow-vstd" ) ;
+        LONG lVideoStd = 0L ;
+        if ( psz_vstd )
+            lVideoStd = AnalogVideoStd_GetCode( psz_vstd ) ;
+        if ( lVideoStd < 0 )
+        {
+            msg_Warn( p_this, "Invalid analog video standart: %s. Skipping it.", psz_vstd ) ;
+            lVideoStd = 0L ;
+        }
+        if ( lVideoStd )
+        {
+            /*Get the AnalogVideoDecoder Interface */
+            IAMAnalogVideoDecoder *pAVD;
+            if( SUCCEEDED( p_device_filter->QueryInterface( IID_IAMAnalogVideoDecoder,
+                                                (void **)&pAVD )) )
+            {
+                if (FAILED( pAVD->put_TVFormat( lVideoStd ) ) )
+                {
+                    msg_Err( p_this, "Could not set analog video standart %s for device %s (is it supported?)", psz_vstd, devicename.c_str() ) ;
+                    /* force abort of device open */
+                    media_count = 0 ;
+                }
+                pAVD->Release() ;
+            }
+            else
+                msg_Warn( p_this, "Trying to set an analog video standart on a digital or unsupported device (%s)", devicename.c_str() );
+        }
+        free( psz_vstd ) ;
+    } //end if b_audio
+
     if( media_count > 0 )
     {
         mt = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * media_count);
@@ -1291,7 +1388,7 @@ static size_t EnumDeviceCaps( vlc_object_t *p_this, IBaseFilter *p_filter,
 
         if( S_OK == p_output_pin->QueryPinInfo( &info ) )
         {
-            msg_Dbg( p_this, "EnumDeviceCaps: %s pin: %S",
+            msg_Dbg( p_this, "EnumDeviceCaps: %s pin: %s",
                      info.dir == PINDIR_INPUT ? "input" : "output",
                      info.achName );
             if( info.pFilter ) info.pFilter->Release();
@@ -1314,7 +1411,7 @@ static size_t EnumDeviceCaps( vlc_object_t *p_this, IBaseFilter *p_filter,
                 p_output_pin->Release();
                 continue;
             }
-            msg_Dbg( p_this, "EnumDeviceCaps: trying pin %S", info.achName );
+            msg_Dbg( p_this, "EnumDeviceCaps: trying pin %s", info.achName );
         }
 
         AM_MEDIA_TYPE *p_mt;
@@ -2008,14 +2105,13 @@ static int ConfigDevicesCallback( vlc_object_t *p_this, char const *psz_name,
     module_config_t *p_item;
     bool b_audio = false;
 
-    /* Initialize OLE/COM */
-    CoInitialize( 0 );
-
     p_item = config_FindConfig( p_this, psz_name );
     if( !p_item ) return VLC_SUCCESS;
-
     if( !strcmp( psz_name, "dshow-adev" ) ) b_audio = true;
 
+    /* Initialize OLE/COM */
+    CoInitialize( 0 );
+
     string devicename;
 
     if( newval.psz_string && *newval.psz_string )
@@ -2029,7 +2125,12 @@ static int ConfigDevicesCallback( vlc_object_t *p_this, char const *psz_name,
 
         /* Enumerate devices */
         FindCaptureDevice( p_this, NULL, &list_devices, b_audio );
-        if( !list_devices.size() ) return VLC_EGENERIC;
+        if( !list_devices.size() )
+        {
+            /* Uninitialize OLE/COM */
+            CoUninitialize();
+            return VLC_EGENERIC;
+        }
         devicename = *list_devices.begin();
     }
 
@@ -2044,6 +2145,81 @@ static int ConfigDevicesCallback( vlc_object_t *p_this, char const *psz_name,
     {
         /* Uninitialize OLE/COM */
         CoUninitialize();
+        msg_Err( p_this, "didn't find device: %s", devicename.c_str() );
+        return VLC_EGENERIC;
+    }
+
+    /* Uninitialize OLE/COM */
+    CoUninitialize();
+
+    return VLC_SUCCESS;
+}
+
+static int UpdateVideoStdsCallback( vlc_object_t *p_this, char const *psz_name,
+                               vlc_value_t newval, vlc_value_t oldval, void * )
+{
+    module_config_t *p_item;
+
+    msg_Dbg( p_this, "Updating Analog video standarts list" );
+
+    p_item = config_FindConfig( p_this, psz_name );
+    if( !p_item ) return VLC_ENOOBJ;
+
+    /* Initialize OLE/COM */
+    CoInitialize( 0 );
+
+    string devicename;
+
+    char* psz_vdev =
+        config_GetPsz( p_this, "dshow-vdev" );
+
+    if( psz_vdev && *psz_vdev )
+    {
+        devicename = psz_vdev;
+        free( psz_vdev );
+    }
+    else
+    {
+        /* If no device name was specified, pick the 1st one */
+        list<string> list_devices;
+
+        /* Enumerate devices */
+        FindCaptureDevice( p_this, NULL, &list_devices, false /*video devices*/ );
+        if( !list_devices.size() )
+        {
+            /* Uninitialize OLE/COM */
+            CoUninitialize();
+            return VLC_EGENERIC;
+        }
+        devicename = *list_devices.begin();
+    }
+
+    /* Get selected (or default) device filter */
+    IBaseFilter *p_device_filter =
+        FindCaptureDevice( p_this, &devicename, NULL, false /*video devices*/ );
+    LONG lVideoStd = 0L;
+    if( p_device_filter )
+    {
+        /*Get the AnalogVideoDecoder Interface */
+        IAMAnalogVideoDecoder *pAVD;
+        if( SUCCEEDED( p_device_filter->QueryInterface( IID_IAMAnalogVideoDecoder,
+                                            (void **)&pAVD )) )
+        {
+            if (FAILED( pAVD->get_TVFormat( &lVideoStd ) ) )
+            {
+                lVideoStd = 0L;
+                msg_Warn( p_this, "could not get analog standarts for device %s", devicename.c_str() ) ;
+            }
+            else
+                msg_Dbg( p_this, "Got analog standarts for device %s", devicename.c_str() ) ;
+            pAVD->Release() ;
+        }
+        p_device_filter->Release();
+    }
+    else
+    {
+        /* Uninitialize OLE/COM */
+        CoUninitialize();
 
         msg_Err( p_this, "didn't find device: %s", devicename.c_str() );
         return VLC_EGENERIC;
@@ -2052,9 +2228,38 @@ static int ConfigDevicesCallback( vlc_object_t *p_this, char const *psz_name,
     /* Uninitialize OLE/COM */
     CoUninitialize();
 
+    int i ;
+    /* Clean-up the current list */
+    for( i = 1; i < p_item->i_list; i++ )
+    {
+        free( const_cast<char *>(p_item->ppsz_list[i]) );
+    }
+
+    const char* psz_vstd ;
+    i = 1;
+    /* Iterate thru all the video standarts in the mask */
+    while ( psz_vstd = AnalogVideoStd_GetNextString( &lVideoStd ) )
+    {
+        if ( i >= p_item->i_list )
+            p_item->ppsz_list =
+            (char **)realloc( p_item->ppsz_list,
+                            ( i+1 ) * sizeof(char *) );
+
+        p_item->ppsz_list[ i++ ] = strdup( psz_vstd ) ;
+    }
+    p_item->i_list = i ;
+    p_item->ppsz_list =
+       (char **)realloc( p_item->ppsz_list,
+                     ( p_item->i_list + 1 ) * sizeof(char *) );
+    p_item->ppsz_list[ p_item->i_list ] = NULL ;
+
+    /* Signal change to the interface */
+    p_item->b_dirty = true;
+
     return VLC_SUCCESS;
 }
 
+
 /*****************************************************************************
  * Properties
  *****************************************************************************/
-- 
1.6.1.3

