]> git.sesse.net Git - vlc/blobdiff - modules/access/dshow/dshow.cpp
DShow: small fixes on error paths
[vlc] / modules / access / dshow / dshow.cpp
index bc0a89b1b475f53bf46b6a633e99ef876ffe5823..b61769ef5a1d46be691ed80c037f4e07ce6951b9 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * dshow.cpp : DirectShow access module for vlc
  *****************************************************************************
- * Copyright (C) 2002, 2003 the VideoLAN team
+ * Copyright (C) 2002-2004, 2006, 2008, 2010 the VideoLAN team
  * $Id$
  *
  * Author: Gildas Bazin <gbazin@videolan.org>
@@ -115,6 +115,8 @@ static const char *const ppsz_amtuner_mode_text[] = { N_("Default"),
     "Size of the video that will be displayed by the " \
     "DirectShow plugin. If you don't specify anything the default size for " \
     "your device will be used. You can specify a standard size (cif, d1, ...) or <width>x<height>.")
+#define ASPECT_TEXT N_("Picture aspect-ratio n:m")
+#define ASPECT_LONGTEXT N_("Define input picture aspect-ratio to use. Default is 4:3" )
 #define CHROMA_TEXT N_("Video input chroma format")
 #define CHROMA_LONGTEXT N_( \
     "Force the DirectShow video input to use a specific chroma format " \
@@ -134,6 +136,10 @@ static const char *const ppsz_amtuner_mode_text[] = { N_("Default"),
 #define CHANNEL_LONGTEXT N_( \
     "Set the TV channel the tuner will set to " \
     "(0 means default)." )
+#define TVFREQ_TEXT N_("Tuner Frequency")
+#define TVFREQ_LONGTEXT N_(  "This overrides the channel. Measured in Hz." )
+#define STANDARD_TEXT N_( "Standard" )
+#define STANDARD_LONGTEXT N_( "Video standard (Default, SECAM_D, PAL_B, NTSC_M, etc...)." )
 #define COUNTRY_TEXT N_("Tuner country code")
 #define COUNTRY_LONGTEXT N_( \
     "Set the tuner country code that establishes the current " \
@@ -174,6 +180,31 @@ static const char *const ppsz_amtuner_mode_text[] = { N_("Default"),
 #define AUDIO_BITSPERSAMPLE_LONGTEXT N_( \
     "Select audio input format with the given bits/sample (if non 0)" )
 
+static const int i_standards_list[] =
+    {
+        KS_AnalogVideo_None,
+        KS_AnalogVideo_NTSC_M, KS_AnalogVideo_NTSC_M_J, KS_AnalogVideo_NTSC_433,
+        KS_AnalogVideo_PAL_B, KS_AnalogVideo_PAL_D, KS_AnalogVideo_PAL_G,
+        KS_AnalogVideo_PAL_H, KS_AnalogVideo_PAL_I, KS_AnalogVideo_PAL_M,
+        KS_AnalogVideo_PAL_N, KS_AnalogVideo_PAL_60,
+        KS_AnalogVideo_SECAM_B, KS_AnalogVideo_SECAM_D, KS_AnalogVideo_SECAM_G,
+        KS_AnalogVideo_SECAM_H, KS_AnalogVideo_SECAM_K, KS_AnalogVideo_SECAM_K1,
+        KS_AnalogVideo_SECAM_L, KS_AnalogVideo_SECAM_L1,
+        KS_AnalogVideo_PAL_N_COMBO
+    };
+static const char *const ppsz_standards_list_text[] =
+    {
+        N_("Default"),
+        "NTSC_M", "NTSC_M_J", "NTSC_443",
+        "PAL_B", "PAL_D", "PAL_G",
+        "PAL_H", "PAL_I", "PAL_M",
+        "PAL_N", "PAL_60",
+        "SECAM_B", "SECAM_D", "SECAM_G",
+        "SECAM_H", "SECAM_K", "SECAM_K1",
+        "SECAM_L", "SECAM_L1",
+        "PAL_N_COMBO"
+    };
+
 static int  CommonOpen ( vlc_object_t *, access_sys_t *, bool );
 static void CommonClose( vlc_object_t *, access_sys_t * );
 
@@ -203,6 +234,8 @@ vlc_module_begin ()
 
     add_string( "dshow-size", NULL, NULL, SIZE_TEXT, SIZE_LONGTEXT, false)
 
+    add_string( "dshow-aspect-ratio", "4:3", NULL, ASPECT_TEXT, ASPECT_LONGTEXT, false)
+
     add_string( "dshow-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true )
 
     add_float( "dshow-fps", 0.0f, NULL, FPS_TEXT, FPS_LONGTEXT, true )
@@ -214,9 +247,16 @@ vlc_module_begin ()
     add_integer( "dshow-tuner-channel", 0, NULL, CHANNEL_TEXT, CHANNEL_LONGTEXT,
                 true )
 
+    add_integer( "dshow-tuner-frequency", 0, NULL, TVFREQ_TEXT, TVFREQ_LONGTEXT,
+                true )
+
     add_integer( "dshow-tuner-country", 0, NULL, COUNTRY_TEXT, COUNTRY_LONGTEXT,
                 true )
 
+    add_integer( "dshow-tuner-standard", 0, NULL, STANDARD_TEXT, STANDARD_LONGTEXT,
+                false )
+        change_integer_list( i_standards_list, ppsz_standards_list_text, NULL )
+
     add_integer( "dshow-tuner-input", 0, NULL, TUNER_INPUT_TEXT,
                  TUNER_INPUT_LONGTEXT, true )
         change_integer_list( pi_tuner_input, ppsz_tuner_input_text, NULL )
@@ -256,6 +296,7 @@ vlc_module_begin ()
 
 vlc_module_end ()
 
+
 /*****************************************************************************
  * DirectShow elementary stream descriptor
  *****************************************************************************/
@@ -422,6 +463,10 @@ static int CommonOpen( vlc_object_t *p_this, access_sys_t *p_sys,
     var_Create( p_this, "dshow-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
     var_Create( p_this, "dshow-tuner-channel",
                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+    var_Create( p_this, "dshow-tuner-frequency",
+                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+    var_Create( p_this, "dshow-tuner-standard",
+                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
     var_Create( p_this, "dshow-tuner-country",
                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
     var_Create( p_this, "dshow-tuner-input",
@@ -437,6 +482,7 @@ static int CommonOpen( vlc_object_t *p_this, access_sys_t *p_sys,
     var_Create( p_this, "dshow-video-output", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
     var_Create( p_this, "dshow-audio-output", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
 
+
     /* Initialize some data */
     p_sys->i_streams = 0;
     p_sys->pp_streams = NULL;
@@ -643,12 +689,25 @@ static int DemuxOpen( vlc_object_t *p_this )
 
         if( p_stream->mt.majortype == MEDIATYPE_Video )
         {
+            char *psz_aspect = var_CreateGetString( p_this, "dshow-aspect-ratio" );
+            char *psz_delim = !EMPTY_STR( psz_aspect ) ? strchr( psz_aspect, ':' ) : NULL;
+
             es_format_Init( &fmt, VIDEO_ES, p_stream->i_fourcc );
 
             fmt.video.i_width  = p_stream->header.video.bmiHeader.biWidth;
             fmt.video.i_height = p_stream->header.video.bmiHeader.biHeight;
-            fmt.video.i_sar_num = 4 * fmt.video.i_height;
-            fmt.video.i_sar_den = 4 * fmt.video.i_width;
+
+            if( psz_delim )
+            {
+                fmt.video.i_sar_num = atoi( psz_aspect ) * fmt.video.i_height;
+                fmt.video.i_sar_den = atoi( psz_delim + 1 ) * fmt.video.i_width;
+            }
+            else
+            {
+                fmt.video.i_sar_num = 4 * fmt.video.i_height;
+                fmt.video.i_sar_den = 3 * fmt.video.i_width;
+            }
+            free( psz_aspect );
 
             if( !p_stream->header.video.bmiHeader.biCompression )
             {
@@ -659,10 +718,12 @@ static int DemuxOpen( vlc_object_t *p_this )
             /* Setup rgb mask for RGB formats */
             if( p_stream->i_fourcc == VLC_CODEC_RGB24 )
             {
-                /* This is in BGR format */
-                fmt.video.i_bmask = 0x00ff0000;
+                /* This is in RGB format
+            http://msdn.microsoft.com/en-us/library/dd407253%28VS.85%29.aspx?ppud=4
+                 */
+                fmt.video.i_rmask = 0x00ff0000;
                 fmt.video.i_gmask = 0x0000ff00;
-                fmt.video.i_rmask = 0x000000ff;
+                fmt.video.i_bmask = 0x000000ff;
             }
 
             if( p_stream->header.video.AvgTimePerFrame )
@@ -1708,7 +1769,7 @@ static block_t *ReadCompressed( access_t *p_access )
 
     while( 1 )
     {
-        if( !vlc_object_alive (p_access) || p_access->b_error ) return 0;
+        if( !vlc_object_alive (p_access) ) return NULL;
 
         /* Get new sample/frame from the elementary stream (blocking). */
         vlc_mutex_lock( &p_sys->lock );
@@ -1847,9 +1908,8 @@ static int Demux( demux_t *p_demux )
  *****************************************************************************/
 static int AccessControl( access_t *p_access, int i_query, va_list args )
 {
-    bool   *pb_bool;
-    int          *pi_int;
-    int64_t      *pi_64;
+    bool    *pb_bool;
+    int64_t *pi_64;
 
     switch( i_query )
     {
@@ -1865,7 +1925,7 @@ static int AccessControl( access_t *p_access, int i_query, va_list args )
     /* */
     case ACCESS_GET_PTS_DELAY:
         pi_64 = (int64_t*)va_arg( args, int64_t * );
-        *pi_64 = (int64_t)var_GetInteger( p_access, "dshow-caching" ) * 1000;
+        *pi_64 = var_GetInteger( p_access, "dshow-caching" ) * 1000;
         break;
 
     /* */
@@ -1889,8 +1949,8 @@ static int AccessControl( access_t *p_access, int i_query, va_list args )
  ****************************************************************************/
 static int DemuxControl( demux_t *p_demux, int i_query, va_list args )
 {
-    bool *pb;
-    int64_t    *pi64;
+    bool    *pb;
+    int64_t *pi64;
 
     switch( i_query )
     {
@@ -1905,7 +1965,7 @@ static int DemuxControl( demux_t *p_demux, int i_query, va_list args )
 
     case DEMUX_GET_PTS_DELAY:
         pi64 = (int64_t*)va_arg( args, int64_t * );
-        *pi64 = (int64_t)var_GetInteger( p_demux, "dshow-caching" ) * 1000;
+        *pi64 = var_GetInteger( p_demux, "dshow-caching" ) * 1000;
         return VLC_SUCCESS;
 
     case DEMUX_GET_TIME:
@@ -1962,7 +2022,7 @@ static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
     /* Uninitialize OLE/COM */
     CoUninitialize();
 
-    if( !list_devices.size() ) return VLC_SUCCESS;
+    if( list_devices.empty() ) return VLC_SUCCESS;
 
     p_item->ppsz_list = (char**)xrealloc( p_item->ppsz_list,
                           (list_devices.size()+3) * sizeof(char *) );
@@ -2024,7 +2084,7 @@ 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() )
+        if( list_devices.empty() )
         {
             CoUninitialize();
             return VLC_EGENERIC;
@@ -2197,7 +2257,7 @@ static void ShowTunerProperties( vlc_object_t *p_this,
 static void ConfigTuner( vlc_object_t *p_this, ICaptureGraphBuilder2 *p_graph,
                          IBaseFilter *p_device_filter )
 {
-    int i_channel, i_country, i_input, i_amtuner_mode;
+    int i_channel, i_country, i_input, i_amtuner_mode, i_standard, i_frequency;
     long l_modes = 0;
     IAMTVTuner *p_TV;
     HRESULT hr;
@@ -2208,11 +2268,15 @@ static void ConfigTuner( vlc_object_t *p_this, ICaptureGraphBuilder2 *p_graph,
     i_country = var_GetInteger( p_this, "dshow-tuner-country" );
     i_input = var_GetInteger( p_this, "dshow-tuner-input" );
     i_amtuner_mode = var_GetInteger( p_this, "dshow-amtuner-mode" );
+    i_frequency = var_GetInteger( p_this, "dshow-tuner-frequency" );
+    i_standard =
+        i_standards_list[var_CreateGetInteger( p_this, "dshow-tuner-standard" )];
+
+    if( !i_channel && !i_frequency && !i_country && !i_input ) return; /* Nothing to do */
 
-    if( !i_channel && !i_country && !i_input ) return; /* Nothing to do */
+    msg_Dbg( p_this, "tuner config: channel %i, frequency %i, country %i, input type %i, standard %s",
+             i_channel, i_frequency, i_country, i_input, ppsz_standards_list_text[i_standard] );
 
-    msg_Dbg( p_this, "tuner config: channel %i, country %i, input type %i",
-             i_channel, i_country, i_input );
 
     hr = p_graph->FindInterface( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved,
                                  p_device_filter, IID_IAMTVTuner,
@@ -2247,7 +2311,109 @@ static void ConfigTuner( vlc_object_t *p_this, ICaptureGraphBuilder2 *p_graph,
     else if( i_input == 2 ) p_TV->put_InputType( 0, TunerInputAntenna );
 
     p_TV->put_CountryCode( i_country );
-    p_TV->put_Channel( i_channel, AMTUNER_SUBCHAN_NO_TUNE,
+
+    if( i_frequency <= 0 ) p_TV->put_Channel( i_channel, AMTUNER_SUBCHAN_NO_TUNE,
                        AMTUNER_SUBCHAN_NO_TUNE );
+
+    if( i_frequency > 0 || i_standard > 0) {
+        IKsPropertySet *pKs = NULL;
+        DWORD dw_supported = 0;
+        KSPROPERTY_TUNER_MODE_CAPS_S ModeCaps;
+        KSPROPERTY_TUNER_FREQUENCY_S Frequency;
+        KSPROPERTY_TUNER_STANDARD_S Standard;
+
+        hr = p_TV->QueryInterface(IID_IKsPropertySet,(void **)&pKs);
+        if (FAILED(hr))
+        {
+            msg_Dbg( p_this, "Couldn't QI for IKsPropertySet" );
+            p_TV->Release();
+            return;
+        }
+
+        memset(&ModeCaps,0,sizeof(KSPROPERTY_TUNER_MODE_CAPS_S));
+        memset(&Frequency,0,sizeof(KSPROPERTY_TUNER_FREQUENCY_S));
+        memset(&Standard,0,sizeof(KSPROPERTY_TUNER_STANDARD_S));
+        ModeCaps.Mode = AMTUNER_MODE_TV;
+
+        hr = pKs->QuerySupported(PROPSETID_TUNER,
+                KSPROPERTY_TUNER_MODE_CAPS,&dw_supported);
+        if(SUCCEEDED(hr) && dw_supported&KSPROPERTY_SUPPORT_GET)
+        {
+            DWORD cbBytes=0;
+            hr = pKs->Get(PROPSETID_TUNER,KSPROPERTY_TUNER_MODE_CAPS,
+                INSTANCEDATA_OF_PROPERTY_PTR(&ModeCaps),
+                INSTANCEDATA_OF_PROPERTY_SIZE(ModeCaps),
+                &ModeCaps,
+                sizeof(ModeCaps),
+                &cbBytes);
+        }
+        else
+        {
+            msg_Dbg( p_this, "KSPROPERTY_TUNER_MODE_CAPS not supported!" );
+            goto free_on_error;
+        }
+
+        msg_Dbg( p_this, "Frequency range supproted from %d to %d.", ModeCaps.MinFrequency, ModeCaps.MaxFrequency);
+        msg_Dbg( p_this, "Video standards supproted by the tuner: ");
+        for(int i = 0 ; i < ARRAY_SIZE(ppsz_standards_list_text); i++) {
+            if(ModeCaps.StandardsSupported & i_standards_list[i])
+                msg_Dbg( p_this, "%s, ", ppsz_standards_list_text[i]);
+        }
+
+        if(i_frequency > 0) {
+            Frequency.Frequency=i_frequency;
+            if(ModeCaps.Strategy==KS_TUNER_STRATEGY_DRIVER_TUNES)
+                Frequency.TuningFlags=KS_TUNER_TUNING_FINE;
+            else
+                Frequency.TuningFlags=KS_TUNER_TUNING_EXACT;
+
+            if(i_frequency>=ModeCaps.MinFrequency && i_frequency<=ModeCaps.MaxFrequency)
+            {
+
+                hr = pKs->Set(PROPSETID_TUNER,
+                    KSPROPERTY_TUNER_FREQUENCY,
+                    INSTANCEDATA_OF_PROPERTY_PTR(&Frequency),
+                    INSTANCEDATA_OF_PROPERTY_SIZE(Frequency),
+                    &Frequency,
+                    sizeof(Frequency));
+                if(FAILED(hr))
+                {
+                    msg_Dbg( p_this, "Couldn't set KSPROPERTY_TUNER_FREQUENCY!" );
+                    goto free_on_error;
+                }
+            }
+            else
+            {
+                msg_Dbg( p_this, "Requested frequency exceeds the supported range!" );
+                goto free_on_error;
+            }
+        }
+
+        if(i_standard > 0) {
+            if(i_standard & ModeCaps.StandardsSupported )
+            {
+                Standard.Standard = i_standard;
+                hr = pKs->Set(PROPSETID_TUNER,
+                    KSPROPERTY_TUNER_STANDARD,
+                    INSTANCEDATA_OF_PROPERTY_PTR(&Standard),
+                    INSTANCEDATA_OF_PROPERTY_SIZE(Standard),
+                    &Standard,
+                    sizeof(Standard));
+                if(FAILED(hr))
+                {
+                    msg_Dbg( p_this, "Couldn't set KSPROPERTY_TUNER_STANDARD!" );
+                    goto free_on_error;
+                }
+            }
+            else
+            {
+                msg_Dbg( p_this, "Requested video standard is not supported by the tuner!" );
+                goto free_on_error;
+            }
+        }
+free_on_error:
+        pKs->Release();
+    }
+
     p_TV->Release();
 }