changeset 24744:d81eef9beb1b

DirectShow based tv:// driver for win32 Teletext is also supported (but 625 system parameters are hardcoded). pthreads is required for teletext. Code is still experimental.
author voroshil
date Sat, 13 Oct 2007 17:14:39 +0000
parents acb856c03bd8
children 97b57f501f3a
files DOCS/man/en/mplayer.1 cfg-common.h configure help/help_mp-en.h stream/Makefile stream/stream_tv.c stream/tv.c stream/tv.h stream/tvi_dshow.c stream/tvi_dshow.h
diffstat 10 files changed, 4175 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/DOCS/man/en/mplayer.1	Sat Oct 13 14:16:37 2007 +0000
+++ b/DOCS/man/en/mplayer.1	Sat Oct 13 17:14:39 2007 +0000
@@ -1909,6 +1909,23 @@
 Useful when the teletext system uses a non-latin character set, but language
 codes are not transmitted via teletext type 28 packets for some reason.
 To see a list of supported language codes set this option to \-1.
+.IPs "hidden_video_renderer (dshow only)"
+Terminate stream with video renderer instead of Null renderer (default: off).
+Will help if video freezes but audio does not.
+NOTE: May not work with \-vo directx and \-vf crop combination.
+.IPs "hidden_vp_renderer (dshow only)"
+Terminate VideoPort pin stream with video renderer 
+instead of removing it from the graph (default: off).
+Useful if your card has a VideoPort pin and video is choppy.
+NOTE: May not work with \-vo directx and \-vf crop combination.
+.IPs "system_clock (dshow only)"
+Use system clock as sync source instead of the default graph clock (usually the clock 
+from one of the live sources in graph).
+.IPs "normalize_audio_chunks (dshow only)"
+Create audio chunks with a time length equal to
+video frame time length (default: off).
+Some audio cards create audio chunks about 0.5s in size, resulting in
+choppy video when using immediatemode=0.
 .RE
 .
 .TP
--- a/cfg-common.h	Sat Oct 13 14:16:37 2007 +0000
+++ b/cfg-common.h	Sat Oct 13 17:14:39 2007 +0000
@@ -426,7 +426,7 @@
 	{"chanlist", &stream_tv_defaults.chanlist, CONF_TYPE_STRING, 0, 0, 0, NULL},
 	{"norm", &stream_tv_defaults.norm, CONF_TYPE_STRING, 0, 0, 0, NULL},
 	{"automute", &stream_tv_defaults.automute, CONF_TYPE_INT, CONF_RANGE, 0, 255, NULL},
-#ifdef HAVE_TV_V4L2
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
 	{"normid", &stream_tv_defaults.normid, CONF_TYPE_INT, 0, 0, 0, NULL},
 #endif
 	{"width", &stream_tv_defaults.width, CONF_TYPE_INT, 0, 0, 4096, NULL},
@@ -440,9 +440,12 @@
 	{"hue", &stream_tv_defaults.hue, CONF_TYPE_INT, CONF_RANGE, -100, 100, NULL},
 	{"saturation", &stream_tv_defaults.saturation, CONF_TYPE_INT, CONF_RANGE, -100, 100, NULL},
 	{"gain", &stream_tv_defaults.gain, CONF_TYPE_INT, CONF_RANGE, -1, 100, NULL},
-#if defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2)
+#if defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
+	{"buffersize", &stream_tv_defaults.buffer_size, CONF_TYPE_INT, CONF_RANGE, 16, 1024, NULL},
 	{"amode", &stream_tv_defaults.amode, CONF_TYPE_INT, CONF_RANGE, 0, 3, NULL},
 	{"volume", &stream_tv_defaults.volume, CONF_TYPE_INT, CONF_RANGE, 0, 65535, NULL},
+#endif
+#if defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2)
 	{"bass", &stream_tv_defaults.bass, CONF_TYPE_INT, CONF_RANGE, 0, 65535, NULL},
 	{"treble", &stream_tv_defaults.treble, CONF_TYPE_INT, CONF_RANGE, 0, 65535, NULL},
 	{"balance", &stream_tv_defaults.balance, CONF_TYPE_INT, CONF_RANGE, 0, 65535, NULL},
@@ -464,6 +467,16 @@
 	{"tlang", &stream_tv_defaults.tlang, CONF_TYPE_INT, CONF_RANGE, -1, 0x7f, NULL},
 #endif /* HAVE_TV_TELETEXT */
 	{"audioid", &stream_tv_defaults.audio_id, CONF_TYPE_INT, CONF_RANGE, 0, 9, NULL},
+#ifdef HAVE_TV_DSHOW
+	{"hidden_video_renderer", &stream_tv_defaults.hidden_video_renderer, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+	{"nohidden_video_renderer", &stream_tv_defaults.hidden_video_renderer, CONF_TYPE_FLAG, 0, 0, 0, NULL},
+	{"hidden_vp_renderer", &stream_tv_defaults.hidden_vp_renderer, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+	{"nohidden_vp_renderer", &stream_tv_defaults.hidden_vp_renderer, CONF_TYPE_FLAG, 0, 0, 0, NULL},
+	{"system_clock", &stream_tv_defaults.system_clock, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+	{"nosystem_clock", &stream_tv_defaults.system_clock, CONF_TYPE_FLAG, 0, 0, 0, NULL},
+	{"normalize_audio_chunks", &stream_tv_defaults.normalize_audio_chunks, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+	{"nonormalize_audio_chunks", &stream_tv_defaults.normalize_audio_chunks, CONF_TYPE_FLAG, 0, 0, 0, NULL},
+#endif
 	{NULL, NULL, 0, 0, 0, 0, NULL}
 };
 #endif /* USE_TV */
--- a/configure	Sat Oct 13 14:16:37 2007 +0000
+++ b/configure	Sat Oct 13 17:14:39 2007 +0000
@@ -612,6 +612,7 @@
 _tv_v4l1=auto
 _tv_v4l2=auto
 _tv_bsdbt848=auto
+_tv_dshow=auto
 _tv_teletext=auto
 _pvr=auto
 _network=yes
@@ -975,6 +976,8 @@
   --disable-tv-v4l1)	_tv_v4l1=no	;;
   --enable-tv-v4l2)	_tv_v4l2=yes	;;
   --disable-tv-v4l2)	_tv_v4l2=no	;;
+  --enable-tv-dshow)	_tv_dshow=yes	;;
+  --disable-tv-dshow)	_tv_dshow=no	;;
   --enable-tv-teletext)    _tv_teletext=yes        ;;
   --disable-tv-teletext)    _tv_teletext=no        ;;
   --enable-radio)       _radio=yes	;;
@@ -6805,6 +6808,32 @@
 fi #if bsd
 
 
+echocheck "DirectShow TV interface"
+if test "$_tv_dshow" = auto ; then
+  _tv_dshow=no
+  if test "$_tv" = yes && win32 ; then
+    cat > $TMPC <<EOF
+#include <ole2.h>
+int main(void) { 
+    void* p;
+    CoCreateInstance((GUID*)&GUID_NULL, NULL, CLSCTX_INPROC_SERVER, &GUID_NULL, &p);
+    return 0; 
+}
+EOF
+    cc_check -lole32 -luuid && _tv_dshow=yes
+  fi
+fi
+if test "$_tv_dshow" = yes ; then
+  _inputmodules="tv-dshow $_inputmodules"
+  _def_tv_dshow='#define HAVE_TV_DSHOW 1'
+  _ld_extra="$_ld_extra -lole32 -luuid"
+else
+  _noinputmodules="tv-dshow $_noinputmodules"
+  _def_tv_dshow='#undef HAVE_TV_DSHOW'
+fi
+echores "$_tv_dshow"
+
+
 echocheck "Video 4 Linux TV interface"
 if test "$_tv_v4l1" = auto ; then
   _tv_v4l1=no
@@ -6859,8 +6888,8 @@
 echocheck "TV teletext interface"
 if test "$_tv_teletext" = auto ; then
   _tv_teletext=no
-  if test "$_freetype" = yes && test "$_pthreads" = yes ; then
-    if test "$_tv_v4l2" = yes || test "$_v4l" = yes ; then
+  if test "$_freetype" = yes && test "$_pthreads" = yes; then
+    if test "$_tv_v4l2" = yes || test "$_v4l" = yes || test "$_tv_dshow" = yes; then
       _tv_teletext=yes
     fi
   fi
@@ -7621,6 +7650,7 @@
 TV_V4L  = $_tv_v4l
 TV_V4L1 = $_tv_v4l1
 TV_V4L2 = $_tv_v4l2
+TV_DSHOW = $_tv_dshow
 TV_BSDBT848 = $_tv_bsdbt848
 TV_TELETEXT = $_tv_teletext
 AUDIO_INPUT = $_audio_input
@@ -8167,6 +8197,9 @@
 /* Enable Video 4 Linux 2 TV interface support */
 $_def_tv_v4l2
 
+/* Enable DirectShow TV interface support */
+$_def_tv_dshow
+
 /* *BSD BrookTree headers */
 $_def_ioctl_meteor_h_name
 $_def_ioctl_bt848_h_name
--- a/help/help_mp-en.h	Sat Oct 13 14:16:37 2007 +0000
+++ b/help/help_mp-en.h	Sat Oct 13 17:14:39 2007 +0000
@@ -2099,3 +2099,49 @@
 #define MSGTR_TV_Bt848UnableToStopCapture "tvi_bsdbt848: Unable to stop capture. Error: %s\n"
 #define MSGTR_TV_TTSupportedLanguages "Supported Teletext languages:\n"
 #define MSGTR_TV_TTSelectedLanguage "Selected default teletext language: %s\n"
+
+//tvi_dshow.c
+#define MSGTR_TVI_DS_UnableConnectInputVideoDecoder  "Unable to connect given input to video decoder. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableConnectInputAudioDecoder  "Unable to connect given input to audio decoder. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableSelectVideoFormat "tvi_dshow: Unable to select video format. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableSelectAudioFormat "tvi_dshow: Unable to select audio format. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableGetMediaControlInterface "tvi_dshow: Unable to get IMediaControl interface. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableStartGraph "tvi_dshow: Unable to start graph! Error:0x%x\n"
+#define MSGTR_TVI_DS_DeviceNotFound "tvi_dshow: Device #%d not found\n"
+#define MSGTR_TVI_DS_UnableGetDeviceName "tvi_dshow: Unable to get name for device #%d\n"
+#define MSGTR_TVI_DS_UsingDevice "tvi_dshow: Using device #%d: %s\n"
+#define MSGTR_TVI_DS_DeviceName  "tvi_dshow: Device #%d: %s\n"
+#define MSGTR_TVI_DS_DirectGetFreqFailed "tvi_dshow: Unable to get frequency directly. OS built-in channels table will be used.\n"
+#define MSGTR_TVI_DS_DirectSetFreqFailed "tvi_dshow: Unable to set frequency directly. OS built-in channels table will be used.\n"
+#define MSGTR_TVI_DS_SupportedNorms "tvi_dshow: supported norms:"
+#define MSGTR_TVI_DS_AvailableVideoInputs "tvi_dshow: available video inputs:"
+#define MSGTR_TVI_DS_AvailableAudioInputs "tvi_dshow: available audio inputs:"
+//following phrase will be printed near the selected audio/video input
+#define MSGTR_TVI_DS_InputSelected "(selected)"
+#define MSGTR_TVI_DS_UnableExtractFreqTable "tvi_dshow: Unable to load frequency table from kstvtune.ax\n"
+#define MSGTR_TVI_DS_WrongDeviceParam "tvi_dshow: Wrong device parameter: %s\n"
+#define MSGTR_TVI_DS_WrongDeviceIndex "tvi_dshow: Wrong device index: %d\n"
+#define MSGTR_TVI_DS_WrongADeviceParam "tvi_dshow: Wrong adevice parameter: %s\n"
+#define MSGTR_TVI_DS_WrongADeviceIndex "tvi_dshow: Wrong adevice index: %d\n"
+
+#define MSGTR_TVI_DS_SamplerateNotsupported "tvi_dshow: Samplerate %d is not supported by device. Failing back to first available.\n"
+#define MSGTR_TVI_DS_VideoAdjustigNotSupported "tvi_dshow: Adjusting of brightness/hue/saturation/contrast is not supported by device\n"
+
+#define MSGTR_TVI_DS_ChangingWidthHeightNotSupported "tvi_dshow: Changing video width/height is not supported by device.\n"
+#define MSGTR_TVI_DS_SelectingInputNotSupported  "tvi_dshow: Selection of capture source is not supported by device\n"
+#define MSGTR_TVI_DS_FreqTableLoaded "tvi_dshow: loaded system (%s) frequency table for country id=%d (channels:%d).\n"
+#define MSGTR_TVI_DS_ErrorParsingAudioFormatStruct "tvi_dshow: Unable to parse audio format structure.\n"
+#define MSGTR_TVI_DS_ErrorParsingVideoFormatStruct "tvi_dshow: Unable to parse video format structure.\n"
+#define MSGTR_TVI_DS_UnableSetAudioMode "tvi_dshow: Unable to set audio mode %d. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnsupportedMediaType "tvi_dshow: Unsupported media type passed to %s\n"
+#define MSGTR_TVI_DS_UnableGetsupportedVideoFormats "tvi_dshow: Unable to get supported media formats from video pin. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableGetsupportedAudioFormats "tvi_dshow: Unable to get supported media formats from audio pin. Error:0x%x Disabling audio.\n"
+#define MSGTR_TVI_DS_UnableFindNearestChannel "tvi_dshow: Unable to find nearest channel in system frequency table\n"
+#define MSGTR_TVI_DS_UnableToSetChannel "tvi_dshow: Unable to switch to nearest channel from system frequency table. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableTerminateVPPin "tvi_dshow: Unable to terminate VideoPort pin with any filter in graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableBuildVideoSubGraph "tvi_dshow: Unable to build video chain of capture graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableBuildAudioSubGraph "tvi_dshow: Unable to build audio chain of capture graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableBuildVBISubGraph "tvi_dshow: Unable to build VBI chain of capture graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_GraphInitFailure "tvi_dshow: Directshow graph initialization failure.\n"
+#define MSGTR_TVI_DS_NoVideoCaptureDevice "tvi_dshow: Unable to find video capture device\n"
+#define MSGTR_TVI_DS_NoAudioCaptureDevice "tvi_dshow: Unable to find audio capture device\n"
--- a/stream/Makefile	Sat Oct 13 14:16:37 2007 +0000
+++ b/stream/Makefile	Sat Oct 13 17:14:39 2007 +0000
@@ -52,6 +52,7 @@
 SRCS_COMMON-$(STREAMING_LIVE555) += stream_livedotcom.c
 SRCS_COMMON-$(TV)                += stream_tv.c tv.c frequencies.c tvi_dummy.c
 SRCS_COMMON-$(TV_BSDBT848)       += tvi_bsdbt848.c
+SRCS_COMMON-$(TV_DSHOW)          += tvi_dshow.c
 SRCS_COMMON-$(TV_TELETEXT)       += tvi_vbi.c
 SRCS_COMMON-$(TV_V4L1)           += tvi_v4l.c  audio_in.c
 SRCS_COMMON-$(TV_V4L2)           += tvi_v4l2.c audio_in.c
--- a/stream/stream_tv.c	Sat Oct 13 14:16:37 2007 +0000
+++ b/stream/stream_tv.c	Sat Oct 13 17:14:39 2007 +0000
@@ -36,7 +36,7 @@
     "europe-east", //chanlist
     "pal",         //norm
     0,             //automute
-#ifdef HAVE_TV_V4L2
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
     -1,            //normid
 #endif
     NULL,          //device
@@ -51,15 +51,18 @@
     0,             //immediate;
     44100,         //audiorate;
     0,             //audio_id
-#if defined(HAVE_TV_V4L)
+#if defined(HAVE_TV_V4L) || defined(HAVE_TV_DSHOW)
     -1,            //amode
     -1,            //volume
+#if defined(HAVE_TV_V4L)
     -1,            //bass
     -1,            //treble
     -1,            //balance
     -1,            //forcechan
     0,             //force_audio
+#endif
     -1,            //buffer_size
+#if defined(HAVE_TV_V4L)
     0,             //mjpeg
     2,             //decimation
     90,            //quality
@@ -68,6 +71,7 @@
 #endif
 #endif
     NULL,          //adevice
+#endif
     0,             //brightness
     0,             //contrast
     0,             //hue
@@ -80,7 +84,13 @@
 
     0,             //scan_autostart
     50,            //scan_threshold
-    0.5            //scan_period
+    0.5,            //scan_period
+#ifdef HAVE_TV_DSHOW
+    0,             //hidden_video_renderer;
+    0,             //hidden_vp_renderer;
+    0,             //system_clock;
+    0              //normalize_audio_chunks;
+#endif
 };
 
 #define ST_OFF(f) M_ST_OFF(tv_param_t,f)
--- a/stream/tv.c	Sat Oct 13 14:16:37 2007 +0000
+++ b/stream/tv.c	Sat Oct 13 17:14:39 2007 +0000
@@ -42,6 +42,9 @@
 
 /* enumerating drivers (like in stream.c) */
 extern tvi_info_t tvi_info_dummy;
+#ifdef HAVE_TV_DSHOW
+extern tvi_info_dshow;
+#endif
 #ifdef HAVE_TV_V4L1
 extern tvi_info_t tvi_info_v4l;
 #endif
@@ -63,6 +66,9 @@
 #ifdef HAVE_TV_BSDBT848
     &tvi_info_bsdbt848,
 #endif
+#ifdef HAVE_TV_DSHOW
+    &tvi_info_dshow,
+#endif
     &tvi_info_dummy,
     NULL
 };
@@ -200,9 +206,14 @@
 
 static int norm_from_string(tvi_handle_t *tvh, char* norm)
 {
+    if (1
 #ifdef HAVE_TV_V4L2
-    if (strcmp(tvh->tv_param->driver, "v4l2") != 0) {
+        && strcmp(tvh->tv_param->driver, "v4l2") != 0 &&
 #endif
+#ifdef HAVE_TV_DSHOW
+        && strcmp(tvh->tv_param->driver, "dshow") != 0
+#endif
+    ) {
     if (!strcasecmp(norm, "pal"))
 	return TV_NORM_PAL;
     else if (!strcasecmp(norm, "ntsc"))
@@ -221,7 +232,7 @@
 	mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TV_BogusNormParameter, norm, "PAL");
 	return TV_NORM_PAL;
     }
-#ifdef HAVE_TV_V4L2
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
     } else {
 	tvi_functions_t *funcs = tvh->functions;
 	char str[8];
@@ -361,8 +372,15 @@
     /* set some params got from cmdline */
     funcs->control(tvh->priv, TVI_CONTROL_SPC_SET_INPUT, &tvh->tv_param->input);
 
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
+    if (0 
 #ifdef HAVE_TV_V4L2
-    if (!strcmp(tvh->tv_param->driver, "v4l2") && tvh->tv_param->normid >= 0) {
+    || (!strcmp(tvh->tv_param->driver, "v4l2") && tvh->tv_param->normid >= 0)
+#endif
+#ifdef HAVE_TV_DSHOW
+    || (!strcmp(tvh->tv_param->driver, "dshow") && tvh->tv_param->normid >= 0)
+#endif
+    ) {
 	mp_msg(MSGT_TV, MSGL_V, MSGTR_TV_SelectedNormId, tvh->tv_param->normid);
 	if (funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tvh->tv_param->normid) != TVI_CONTROL_TRUE) {
 	    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_CannotSetNorm);
@@ -376,7 +394,7 @@
     if (funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tvh->norm) != TVI_CONTROL_TRUE) {
 	mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_CannotSetNorm);
     }
-#ifdef HAVE_TV_V4L2
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
     }
 #endif
 
--- a/stream/tv.h	Sat Oct 13 14:16:37 2007 +0000
+++ b/stream/tv.h	Sat Oct 13 17:14:39 2007 +0000
@@ -11,7 +11,7 @@
     char *chanlist;
     char *norm;
     int automute;
-#ifdef HAVE_TV_V4L2
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
     int normid;
 #endif
     char *device;
@@ -26,15 +26,18 @@
     int immediate;
     int audiorate;
     int audio_id;
-#if defined(HAVE_TV_V4L)
+#if defined(HAVE_TV_V4L) || defined(HAVE_TV_DSHOW)
     int amode;
     int volume;
+#if defined(HAVE_TV_V4L)
     int bass;
     int treble;
     int balance;
     int forcechan;
     int force_audio;
+#endif
     int buffer_size;
+#if defined(HAVE_TV_V4L)
     int mjpeg;
     int decimation;
     int quality;
@@ -43,6 +46,7 @@
 #endif
 #endif
     char* adevice;
+#endif
     int brightness;
     int contrast;
     int hue;
@@ -56,6 +60,35 @@
     int scan;
     int scan_threshold;
     float scan_period;
+
+#ifdef HAVE_TV_DSHOW
+    /**
+      Terminate stream with video renderer instead of Null renderer 
+      Will help if video freezes but audio does not.
+      May not work with -vo directx and -vf crop combination.
+    */
+    int hidden_video_renderer;
+    /**
+      For VIVO cards VP pin have to be rendered too.
+      This tweak will cause VidePort pin stream to be terminated with video renderer 
+      instead of removing it from graph.
+      Use if your card have vp pin and video is still choppy.
+      May not work with -vo directx and -vf crop combination.
+    */
+    int hidden_vp_renderer;
+    /**
+      Use system clock as sync source instead of default graph clock (usually the clock 
+      from one of live sources in graph.
+    */
+    int system_clock;
+    /**
+      Some audio cards creates audio chunks with about 0.5 sec size.
+      This can cause choppy video when using mplayer with immediatemode=0
+      Use followingtweak to decrease audio chunk sizes.
+      It will create audio chunks with time length equal to one video frame time.
+    */
+    int normalize_audio_chunks;
+#endif
 } tv_param_t;
   
 extern tv_param_t stream_tv_defaults;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stream/tvi_dshow.c	Sat Oct 13 17:14:39 2007 +0000
@@ -0,0 +1,3298 @@
+/*
+ *     TV support under Win32
+ * 
+ *     (C) 2007 Vladimir Voroshilov <voroshil@gmail.com>.
+ *
+ *     Based on tvi_dummy.c with help of tv.c, tvi_v4l2.c code .
+ *
+ *     -------------------------------------------------------------------------------
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *
+ *     -------------------------------------------------------------------------------
+ *
+ *
+ *     WARNING: This is alpha code!
+ *
+ *     Abilities:
+ *     * Watching TV under Win32 using WDM Capture driver and DirectShow
+ *     * Grabbing synchronized audio/video with mencoder (synchronization is beeing done by DirectShow)
+ *     * If device driver provides IAMStreamConfig interface, user can choose width/height with "-tv height=<h>:width=<w>"
+ *     * Adjusting BRIGHTNESS,HUE,SATURATION,CONTRAST if supported by device
+ *     * Selecting Tuner,S-Video,... as media source
+ *     * User can select used video capture device, passing -tv device=<dev#>
+ *     * User can select used audio input, passing -tv audioid=<input#>
+ *
+ *     options which will not be implemented (probably sometime in future, if possible):
+ *     * alsa
+ *     * mjpeg
+ *     * decimation=<1|2|4>
+ *     * quality=<0\-100>
+ *     * forceaudio
+ *     * forcechan=<1\-2>
+ *     * [volume|bass|treble|balance]
+ *
+ *     Works with:
+ *       - LifeView FlyTV Prime 34FM (SAA7134 based) with driver from Ivan Uskov
+ *     Partially works with:
+ *       - ATI 9200 VIVO based card
+ *       - ATI AIW 7500
+ *       - nVidia Ti-4400
+ * 
+ *     Known bugs:
+ *     * stream goes with 24.93 FPS (NTSC), while reporting 25 FPS (PAL) ?!
+ *     * direct set frequency call does not work ('Insufficient Buffer' error)
+ *     * audio stream goes with about 1 sample/sec rate when capturing sound from audio card
+ *
+ *     TODO:
+ *     * check audio with small buffer on vivo !!!
+ *     * norm for IAMVideoDecoder and for IAMTVtuner - differs !!
+ *     * check how to change TVFormat on VIVO card without tuner
+ *     * Flip image upside-down for RGB formats.
+ *     *
+ *     * remove debug sleep()
+ *     * Add some notes to methods' parameters
+ *     * refactor console messages
+ *     * check using header files and keep only needed
+ *     * add additional comments to methods' bodies
+ *
+ */
+
+
+/// \ingroup tvi_dshow
+
+#include "config.h"
+
+#include <stdio.h>
+#include "libmpcodecs/img_format.h"
+#include "libaf/af_format.h"
+#include "help_mp.h"
+#include "osdep/timer.h"
+
+
+#include "tv.h"
+#include "mp_msg.h"
+#include "frequencies.h"
+
+
+#include "tvi_dshow.h"
+
+static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param);
+
+/*
+*---------------------------------------------------------------------------------------
+*
+*   Data structures
+*
+*---------------------------------------------------------------------------------------
+*/
+/** 
+    information about this file
+*/
+tvi_info_t tvi_info_dshow = {
+    tvi_init_dshow,
+    "DirectShow TV",
+    "dshow",
+    "Vladimir Voroshilov",
+    "Very experimental!! Use with caution"
+};
+
+
+/**
+ringbuffer related info
+*/
+typedef struct {
+    CRITICAL_SECTION *pMutex;	///< pointer to critical section (mutex)
+    char **ringbuffer;		///< ringbuffer array
+    double*dpts;		///< samples' timestamps
+
+    int buffersize;		///< size of buffer in blocks
+    int blocksize;		///< size of individual block
+    int head;			///< index of first valid sample
+    int tail;			///< index of last valid sample
+    int count;			///< count of valid samples in ringbuffer
+    double tStart;              ///< pts of first sample (first sample should have pts 0)
+} grabber_ringbuffer_t;
+
+/**
+     CSampleGrabberCD definition
+*/
+typedef struct CSampleGrabberCB {
+    ISampleGrabberCBVtbl *lpVtbl;
+    int refcount;
+    GUID interfaces[2];
+    grabber_ringbuffer_t *pbuf;
+} CSampleGrabberCB;
+
+typedef struct {
+    int dev_index;              ///< capture device index in device list (defaul: 0, first available device)
+    int adev_index;             ///< audio capture device index in device list (default: -1, not used)
+    int immediate_mode;         ///< immediate mode (no sound capture)
+    int state;                  ///< state: 1-filter graph running, 0-filter graph stopped
+    int direct_setfreq_call;    ///< 0-find nearest channels from system channel list(workaround),1-direct call to set frequency
+    int direct_getfreq_call;    ///< 0-find frequncy from frequency table (workaround),1-direct call to get frequency
+
+    int fcc;                    ///< used video format code (FourCC)
+    int width;                  ///< picture width (default: auto) 
+    int height;                 ///< picture height (default: auto)
+
+    int channels;               ///< number of audio channels (default: auto)
+    int samplerate;             ///< audio samplerate (default: auto)
+
+    long *freq_table;           ///< frequency table (in Hz)
+    int freq_table_len;         ///< length of freq table
+    int first_channel;          ///< channel number of first entry in freq table
+    int input;                  ///< used input
+
+    // video related stuff
+    int nVideoFormatUsed;                   ///< index of used video format
+    AM_MEDIA_TYPE **arpmtVideo;             ///< available video formats
+    VIDEO_STREAM_CONFIG_CAPS **arVideoCaps; ///< capabilities of output video
+    AM_MEDIA_TYPE *pmtVideo;                ///< video stream properties
+    grabber_ringbuffer_t *v_buf;
+    IBaseFilter *pVideoFilter;              ///< interface for capture device
+    IAMStreamConfig *pVideoStreamConfig;    ///< for configuring video stream
+
+    // audio related stuff
+    int nAudioFormatUsed;                   ///< index of used audio format
+    AM_MEDIA_TYPE **arpmtAudio;             ///< available audio formats
+    AUDIO_STREAM_CONFIG_CAPS **arAudioCaps; ///< capabilities of output audio
+    AM_MEDIA_TYPE *pmtAudio;                ///< audio stream properties.
+    grabber_ringbuffer_t *a_buf;
+    IBaseFilter *pAudioFilter;              ///< interface for audio capture device (if adevice passed)
+    IAMStreamConfig *pAudioStreamConfig;    ///< for configuring audio stream
+
+    AM_MEDIA_TYPE *pmtVBI;                  ///< available audio formats
+    grabber_ringbuffer_t *vbi_buf;
+
+    IAMTVTuner *pTVTuner;                   ///< interface for tuner device
+    IGraphBuilder *pGraph;                  ///< filter graph
+    ICaptureGraphBuilder2 *pBuilder;        ///< graph builder
+    IMediaControl *pMediaControl;           ///< interface for controlling graph (start, stop,...)
+    IAMVideoProcAmp *pVideoProcAmp;         ///< for adjusting hue,saturation,etc
+    IAMCrossbar *pCrossbar;                 ///< for selecting input (Tuner,Composite,S-Video,...)
+    DWORD dwRegister;                       ///< allow graphedit to connect to our graph
+    CSampleGrabberCB* pCSGCB;               ///< callback object
+    void *priv_vbi;                         ///< private VBI data structure
+    tt_stream_props tsp;                    ///< data for VBI initialization
+
+    tv_param_t* tv_param;                   ///< TV parameters
+} priv_t;
+
+#include "tvi_def.h"
+
+/**
+ country table entry structure (for loading freq table stored in kstvtuner.ax
+
+ \note
+ structure have to be 2-byte aligned and have 10-byte length!!
+*/
+typedef struct __attribute__((__packed__)) {
+    WORD CountryCode;		///< Country code
+    WORD CableFreqTable;	///< index of resource with frequencies for cable channels
+    WORD BroadcastFreqTable;	///< index of resource with frequencies for broadcast channels
+    DWORD VideoStandard;	///< used video standard 
+} TRCCountryList;
+/**
+    information about image formats
+*/
+typedef struct {
+    uint32_t fmt;		///< FourCC
+    const GUID *subtype;	///< DirectShow's subtype
+    int nBits;			///< number of bits
+    int nCompression;		///< complression
+    int tail;			///< number of additional bytes followed VIDEOINFOHEADER structure
+} img_fmt;
+
+/*
+*---------------------------------------------------------------------------------------
+*
+*   Methods forward declaration
+*
+*---------------------------------------------------------------------------------------
+*/
+static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize,
+			       int blocksize);
+static HRESULT show_filter_info(IBaseFilter * pFilter);
+#if 0 
+//defined in current MinGW release
+HRESULT STDCALL GetRunningObjectTable(DWORD, IRunningObjectTable **);
+HRESULT STDCALL CreateItemMoniker(LPCOLESTR, LPCOLESTR, IMoniker **);
+#endif
+static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t *
+						 pbuf);
+static int set_crossbar_input(priv_t * priv, int input);
+static int subtype2imgfmt(const GUID * subtype);
+
+/*
+*---------------------------------------------------------------------------------------
+*
+*  Global constants and variables
+*
+*---------------------------------------------------------------------------------------
+*/
+/**
+    lookup tables for physical connector types
+ */
+static const struct {
+    long type;
+    char *name;
+} tv_physcon_types[]={
+    {PhysConn_Video_Tuner,           "Tuner"          },
+    {PhysConn_Video_Composite,       "Composite"      },
+    {PhysConn_Video_SVideo,          "S-Video"        },
+    {PhysConn_Video_RGB,             "RGB"            },
+    {PhysConn_Video_YRYBY,           "YRYBY"          },
+    {PhysConn_Video_SerialDigital,   "SerialDigital"  },
+    {PhysConn_Video_ParallelDigital, "ParallelDigital"},
+    {PhysConn_Video_VideoDecoder,    "VideoDecoder"   },
+    {PhysConn_Video_VideoEncoder,    "VideoEncoder"   },
+    {PhysConn_Video_SCART,           "SCART"          },
+    {PhysConn_Video_Black,           "Blaack"         },
+    {PhysConn_Audio_Tuner,           "Tuner"          },
+    {PhysConn_Audio_Line,            "Line"           },
+    {PhysConn_Audio_Mic,             "Mic"            },
+    {PhysConn_Audio_AESDigital,      "AESDiital"      },
+    {PhysConn_Audio_SPDIFDigital,    "SPDIFDigital"   },
+    {PhysConn_Audio_AudioDecoder,    "AudioDecoder"   },
+    {PhysConn_Audio_SCSI,            "SCSI"           },
+    {PhysConn_Video_SCSI,            "SCSI"           },
+    {PhysConn_Audio_AUX,             "AUX"            },
+    {PhysConn_Video_AUX,             "AUX"            },
+    {PhysConn_Audio_1394,            "1394"           },
+    {PhysConn_Video_1394,            "1394"           },
+    {PhysConn_Audio_USB,             "USB"            },
+    {PhysConn_Video_USB,             "USB"            },
+    {-1,                              NULL            }
+};
+
+static const struct {
+    char *chanlist_name;
+    int country_code;
+} tv_chanlist2country[]={
+    {"us-bcast",     1},
+    {"russia",       7},
+    {"argentina",   54},
+    {"japan-bcast", 81},
+    {"china-bcast", 86},
+    {"southafrica", 27},
+    {"australia",   61},
+    {"ireland",    353},
+    {"france",      33},
+    {"italy",       39},
+    {"newzealand",  64},
+    //directshow table uses eastern europe freq table for russia
+    {"europe-east",  7},
+    //directshow table uses western europe freq table for germany
+    {"europe-west", 49},
+    /* cable channels */
+    {"us-cable",     1},
+    {"us-cable-hrc", 1},
+    {"japan-cable", 81},
+    //default is USA
+    {NULL,           1} 
+};
+
+/**
+    array, contains information about various supported (i hope) image formats
+*/
+static const img_fmt img_fmt_list[] = {
+    {IMGFMT_YUY2, &MEDIASUBTYPE_YUY2, 0, IMGFMT_YUY2, 0},
+    {IMGFMT_YV12, &MEDIASUBTYPE_YV12, 0, IMGFMT_YV12, 0},
+    {IMGFMT_IYUV, &MEDIASUBTYPE_IYUV, 0, IMGFMT_IYUV, 0},
+    {IMGFMT_I420, &MEDIASUBTYPE_I420, 0, IMGFMT_I420, 0},
+    {IMGFMT_UYVY, &MEDIASUBTYPE_UYVY, 0, IMGFMT_UYVY, 0},
+    {IMGFMT_YVYU, &MEDIASUBTYPE_YVYU, 0, IMGFMT_YVYU, 0},
+    {IMGFMT_YVU9, &MEDIASUBTYPE_YVU9, 0, IMGFMT_YVU9, 0},
+    {IMGFMT_BGR32, &MEDIASUBTYPE_RGB32, 32, 0, 0},
+    {IMGFMT_BGR24, &MEDIASUBTYPE_RGB24, 24, 0, 0},
+    {IMGFMT_BGR16, &MEDIASUBTYPE_RGB565, 16, 3, 12},
+    {IMGFMT_BGR15, &MEDIASUBTYPE_RGB555, 16, 3, 12},
+    {0, &GUID_NULL, 0, 0, 0}
+};
+
+#define TV_NORMS_COUNT 19
+static const struct {
+    long index;
+    char *name;
+} tv_norms[TV_NORMS_COUNT] = {
+    {
+    AnalogVideo_NTSC_M, "ntsc-m"}, {
+    AnalogVideo_NTSC_M_J, "ntsc-mj"}, {
+    AnalogVideo_NTSC_433, "ntsc-433"}, {
+    AnalogVideo_PAL_B, "pal-b"}, {
+    AnalogVideo_PAL_D, "pal-d"}, {
+    AnalogVideo_PAL_G, "pal-g"}, {
+    AnalogVideo_PAL_H, "pal-h"}, {
+    AnalogVideo_PAL_I, "pal-i"}, {
+    AnalogVideo_PAL_M, "pal-m"}, {
+    AnalogVideo_PAL_N, "pal-n"}, {
+    AnalogVideo_PAL_60, "pal-60"}, {
+    AnalogVideo_SECAM_B, "secam-b"}, {
+    AnalogVideo_SECAM_D, "secam-d"}, {
+    AnalogVideo_SECAM_G, "secam-g"}, {
+    AnalogVideo_SECAM_H, "secam-h"}, {
+    AnalogVideo_SECAM_K, "secam-k"}, {
+    AnalogVideo_SECAM_K1, "secam-k1"}, {
+    AnalogVideo_SECAM_L, "secam-l"}, {
+    AnalogVideo_SECAM_L1, "secam-l1"}
+};
+static long tv_available_norms[TV_NORMS_COUNT];
+static int tv_available_norms_count = 0;
+
+
+static long *tv_available_inputs;
+static int tv_available_inputs_count = 0;
+
+/*
+*---------------------------------------------------------------------------------------
+*
+*  Various GUID definitions
+*
+*---------------------------------------------------------------------------------------
+*/
+/// CLSID definitions (used for CoCreateInstance call)
+DEFINE_GUID(CLSID_SampleGrabber, 0xC1F400A0, 0x3F08, 0x11d3, 0x9F, 0x0B,
+	    0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
+DEFINE_GUID(CLSID_NullRenderer, 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B,
+	    0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
+DEFINE_GUID(CLSID_SystemDeviceEnum, 0x62BE5D10, 0x60EB, 0x11d0, 0xBD, 0x3B,
+	    0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
+DEFINE_GUID(CLSID_CaptureGraphBuilder2, 0xBF87B6E1, 0x8C27, 0x11d0, 0xB3,
+	    0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
+DEFINE_GUID(CLSID_VideoInputDeviceCategory, 0x860BB310, 0x5D01, 0x11d0,
+	    0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
+DEFINE_GUID(CLSID_AudioInputDeviceCategory, 0x33d9a762, 0x90c8, 0x11d0,
+	    0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
+DEFINE_GUID(CLSID_FilterGraph, 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53,
+	    0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
+DEFINE_GUID(CLSID_SystemClock, 0xe436ebb1, 0x524f, 0x11ce, 0x9f, 0x53,
+	    0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
+#ifdef NOT_USED
+DEFINE_GUID(CLSID_CaptureGraphBuilder, 0xBF87B6E0, 0x8C27, 0x11d0, 0xB3,
+	    0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
+DEFINE_GUID(CLSID_VideoPortManager, 0x6f26a6cd, 0x967b, 0x47fd, 0x87, 0x4a,
+	    0x7a, 0xed, 0x2c, 0x9d, 0x25, 0xa2);
+DEFINE_GUID(IID_IPin, 0x56a86891, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20,
+	    0xaf, 0x0b, 0xa7, 0x70);
+DEFINE_GUID(IID_ICaptureGraphBuilder, 0xbf87b6e0, 0x8c27, 0x11d0, 0xb3,
+	    0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5);
+DEFINE_GUID(IID_IFilterGraph, 0x56a8689f, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
+	    0x20, 0xaf, 0x0b, 0xa7, 0x70);
+DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
+	    0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
+#endif
+
+/// IID definitions (used for QueryInterface call)
+DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a,
+	    0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
+DEFINE_GUID(IID_IAMBufferNegotiation, 0x56ED71A0, 0xAF5F, 0x11D0, 0xB3, 0xF0,
+            0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
+DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa,
+	    0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
+DEFINE_GUID(IID_ISampleGrabber, 0x6B652FFF, 0x11FE, 0x4fce, 0x92, 0xAD,
+	    0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F);
+DEFINE_GUID(IID_ISampleGrabberCB, 0x0579154A, 0x2B53, 0x4994, 0xB0, 0xD0,
+	    0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85);
+DEFINE_GUID(IID_ICaptureGraphBuilder2, 0x93e5a4e0, 0x2d50, 0x11d2, 0xab,
+	    0xfa, 0x00, 0xa0, 0xc9, 0xc6, 0xe3, 0x8d);
+DEFINE_GUID(IID_ICreateDevEnum, 0x29840822, 0x5b84, 0x11d0, 0xbd, 0x3b,
+	    0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
+DEFINE_GUID(IID_IGraphBuilder, 0x56a868a9, 0x0ad4, 0x11ce, 0xb0, 0x3a,
+	    0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
+DEFINE_GUID(IID_IAMVideoProcAmp, 0xC6E13360, 0x30AC, 0x11d0, 0xA1, 0x8C,
+	    0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
+DEFINE_GUID(IID_IVideoWindow, 0x56a868b4, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
+	    0x20, 0xaf, 0x0b, 0xa7, 0x70);
+DEFINE_GUID(IID_IMediaControl, 0x56a868b1, 0x0ad4, 0x11ce, 0xb0, 0x3a,
+	    0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
+DEFINE_GUID(IID_IAMTVTuner, 0x211A8766, 0x03AC, 0x11d1, 0x8D, 0x13, 0x00,
+	    0xAA, 0x00, 0xBD, 0x83, 0x39);
+DEFINE_GUID(IID_IAMCrossbar, 0xc6e13380, 0x30ac, 0x11d0, 0xa1, 0x8c, 0x00,
+	    0xa0, 0xc9, 0x11, 0x89, 0x56);
+DEFINE_GUID(IID_IAMStreamConfig, 0xc6e13340, 0x30ac, 0x11d0, 0xa1, 0x8c,
+	    0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56);
+DEFINE_GUID(IID_IAMAudioInputMixer, 0x54C39221, 0x8380, 0x11d0, 0xB3, 0xF0,
+	    0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
+DEFINE_GUID(IID_IAMTVAudio, 0x83EC1C30, 0x23D1, 0x11d1, 0x99, 0xE6, 0x00,
+	    0xA0, 0xC9, 0x56, 0x02, 0x66);
+DEFINE_GUID(IID_IAMAnalogVideoDecoder, 0xC6E13350, 0x30AC, 0x11d0, 0xA1,
+	    0x8C, 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
+DEFINE_GUID(IID_IPropertyBag, 0x55272a00, 0x42cb, 0x11ce, 0x81, 0x35, 0x00,
+	    0xaa, 0x00, 0x4b, 0xb8, 0x51);
+DEFINE_GUID(PIN_CATEGORY_CAPTURE, 0xfb6c4281, 0x0353, 0x11d1, 0x90, 0x5f,
+	    0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
+DEFINE_GUID(PIN_CATEGORY_VIDEOPORT, 0xfb6c4285, 0x0353, 0x11d1, 0x90, 0x5f,
+	    0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
+DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f, 
+            0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
+DEFINE_GUID(PIN_CATEGORY_VBI, 0xfb6c4284, 0x0353, 0x11d1, 0x90, 0x5f,
+            0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
+DEFINE_GUID(PROPSETID_TUNER, 0x6a2e0605, 0x28e4, 0x11d0, 0xa1, 0x8c, 0x00,
+	    0xa0, 0xc9, 0x11, 0x89, 0x56);
+DEFINE_GUID(MEDIATYPE_VBI,   0xf72a76e1, 0xeb0a, 0x11d0, 0xac, 0xe4, 0x00,
+            0x00, 0xc0, 0xcc, 0x16, 0xba);
+
+#define INSTANCEDATA_OF_PROPERTY_PTR(x) (((KSPROPERTY*)(x)) + 1)
+#define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY))
+
+#define DEVICE_NAME_MAX_LEN 2000
+
+/*---------------------------------------------------------------------------------------
+*  Methods, called only from this file
+*---------------------------------------------------------------------------------------*/
+
+void set_buffer_preference(int nDiv,WAVEFORMATEX* pWF,IPin* pOutPin,IPin* pInPin){
+    ALLOCATOR_PROPERTIES prop;
+    IAMBufferNegotiation* pBN;
+    HRESULT hr;
+
+    prop.cbAlign = -1;
+    prop.cbBuffer = pWF->nAvgBytesPerSec/nDiv;
+    if (!prop.cbBuffer)
+        prop.cbBuffer = 1;
+    prop.cbBuffer += pWF->nBlockAlign - 1;
+    prop.cbBuffer -= prop.cbBuffer % pWF->nBlockAlign;
+    prop.cbPrefix = -1;
+    prop.cBuffers = -1;    
+
+    hr=OLE_QUERYINTERFACE(pOutPin,IID_IAMBufferNegotiation,pBN);
+    if(FAILED(hr))
+        mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pOutPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x\n",(unsigned int)hr);
+    else{
+        hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop);
+        if(FAILED(hr))
+            mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow:pOutPin->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr);
+        OLE_RELEASE_SAFE(pBN);
+    }
+    hr=OLE_QUERYINTERFACE(pInPin,IID_IAMBufferNegotiation,pBN);
+    if(FAILED(hr))
+        mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x",(unsigned int)hr);
+    else{
+        hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop);
+        if(FAILED(hr))
+            mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPit->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr);
+        OLE_RELEASE_SAFE(pBN);
+    }
+}
+/*
+*---------------------------------------------------------------------------------------
+*
+*  CSampleGrabberCD class. Used for receiving samples from DirectShow.
+*
+*---------------------------------------------------------------------------------------
+*/
+/// CSampleGrabberCD destructor
+static void CSampleGrabberCB_Destroy(CSampleGrabberCB * This)
+{
+    free(This->lpVtbl);
+    free(This);
+}
+
+/// CSampleGrabberCD IUnknown interface methods implementation
+static long STDCALL CSampleGrabberCB_QueryInterface(ISampleGrabberCB *
+						    This,
+						    const GUID * riid,
+						    void **ppvObject)
+{
+    CSampleGrabberCB *me = (CSampleGrabberCB *) This;
+    GUID *r;
+    unsigned int i = 0;
+    Debug printf("CSampleGrabberCB_QueryInterface(%p) called\n", This);
+    if (!ppvObject)
+	return E_POINTER;
+    for (r = me->interfaces;
+	 i < sizeof(me->interfaces) / sizeof(me->interfaces[0]); r++, i++)
+	if (!memcmp(r, riid, sizeof(*r))) {
+	    OLE_CALL(This, AddRef);
+	    *ppvObject = This;
+	    return 0;
+	}
+    Debug printf("Query failed! (GUID: 0x%x)\n", *(unsigned int *) riid);
+    return E_NOINTERFACE;
+}
+
+static long STDCALL CSampleGrabberCB_AddRef(ISampleGrabberCB * This)
+{
+    CSampleGrabberCB *me = (CSampleGrabberCB *) This;
+    Debug printf("CSampleGrabberCB_AddRef(%p) called (ref:%d)\n", This,
+        	 me->refcount);
+    return ++(me->refcount);
+}
+
+static long STDCALL CSampleGrabberCB_Release(ISampleGrabberCB * This)
+{
+    CSampleGrabberCB *me = (CSampleGrabberCB *) This;
+    Debug printf("CSampleGrabberCB_Release(%p) called (new ref:%d)\n",
+		 This, me->refcount - 1);
+    if (--(me->refcount) == 0)
+	CSampleGrabberCB_Destroy(me);
+    return 0;
+}
+
+
+HRESULT STDCALL CSampleGrabberCB_BufferCB(ISampleGrabberCB * This,
+					  double SampleTime,
+					  BYTE * pBuffer, long lBufferLen)
+{
+    CSampleGrabberCB *this = (CSampleGrabberCB *) This;
+    grabber_ringbuffer_t *rb = this->pbuf;
+
+    if (!lBufferLen)
+	return E_FAIL;
+
+    if (!rb->ringbuffer) {
+	rb->buffersize /= lBufferLen;
+	if (init_ringbuffer(rb, rb->buffersize, lBufferLen) != S_OK)
+	    return E_FAIL;
+    }
+    mp_msg(MSGT_TV, MSGL_DBG4,
+	   "tvi_dshow: BufferCB(%p): len=%ld ts=%f\n", This, lBufferLen, SampleTime);
+    EnterCriticalSection(rb->pMutex);
+    if (rb->count >= rb->buffersize) {
+	rb->head = (rb->head + 1) % rb->buffersize;
+	rb->count--;
+    }
+
+    memcpy(rb->ringbuffer[rb->tail], pBuffer,
+	   lBufferLen < rb->blocksize ? lBufferLen : rb->blocksize);
+    rb->dpts[rb->tail] =  SampleTime;
+    rb->tail = (rb->tail + 1) % rb->buffersize;
+    rb->count++;
+    LeaveCriticalSection(rb->pMutex);
+
+    return S_OK;
+}
+
+/// wrapper. directshow does the same when BufferCB callback is requested
+HRESULT STDCALL CSampleGrabberCB_SampleCB(ISampleGrabberCB * This,
+					  double SampleTime,
+					  LPMEDIASAMPLE pSample)
+{
+    char* buf;
+    long len;
+    long long tStart,tEnd;
+    HRESULT hr;
+    grabber_ringbuffer_t *rb = ((CSampleGrabberCB*)This)->pbuf;
+
+    len=OLE_CALL(pSample,GetSize);
+    tStart=tEnd=0;
+    hr=OLE_CALL_ARGS(pSample,GetTime,&tStart,&tEnd);
+    if(FAILED(hr)){
+        return hr;
+    }
+    mp_msg(MSGT_TV, MSGL_DBG4,"tvi_dshow: SampleCB(%p): %d/%d %f\n", This,rb->count,rb->buffersize,1e-7*tStart);
+    hr=OLE_CALL_ARGS(pSample,GetPointer,(void*)&buf);
+    if(FAILED(hr)){
+        return hr;
+    }
+    hr=CSampleGrabberCB_BufferCB(This,1e-7*tStart,buf,len);
+    return hr;
+
+}
+
+/// main grabbing routine
+static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t *
+						 pbuf)
+{
+    CSampleGrabberCB *This = malloc(sizeof(CSampleGrabberCB));
+    if (!This)
+	return NULL;
+
+    This->lpVtbl = malloc(sizeof(ISampleGrabberVtbl));
+    if (!This->lpVtbl) {
+	CSampleGrabberCB_Destroy(This);
+	return NULL;
+    }
+    This->refcount = 1;
+    This->lpVtbl->QueryInterface = CSampleGrabberCB_QueryInterface;
+    This->lpVtbl->AddRef = CSampleGrabberCB_AddRef;
+    This->lpVtbl->Release = CSampleGrabberCB_Release;
+    This->lpVtbl->SampleCB = CSampleGrabberCB_SampleCB;
+    This->lpVtbl->BufferCB = CSampleGrabberCB_BufferCB;
+
+    This->interfaces[0] = IID_IUnknown;
+    This->interfaces[1] = IID_ISampleGrabberCB;
+
+    This->pbuf = pbuf;
+
+    return This;
+}
+
+/*
+*---------------------------------------------------------------------------------------
+*
+*  ROT related methods (register, unregister)
+*
+*---------------------------------------------------------------------------------------
+*/
+/** 
+Registering graph in ROT. User will be able to connect to graph from GraphEdit.
+*/
+static HRESULT AddToRot(IUnknown * pUnkGraph, DWORD * pdwRegister)
+{
+    IMoniker *pMoniker;
+    IRunningObjectTable *pROT;
+    WCHAR wsz[256];
+    HRESULT hr;
+
+    if (FAILED(GetRunningObjectTable(0, &pROT))) {
+	return E_FAIL;
+    }
+    wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR) pUnkGraph,
+	      GetCurrentProcessId());
+    hr = CreateItemMoniker(L"!", wsz, &pMoniker);
+    if (SUCCEEDED(hr)) {
+	hr = OLE_CALL_ARGS(pROT, Register, ROTFLAGS_REGISTRATIONKEEPSALIVE,
+		       pUnkGraph, pMoniker, pdwRegister);
+	OLE_RELEASE_SAFE(pMoniker);
+    }
+    OLE_RELEASE_SAFE(pROT);
+    return hr;
+}
+
+/// Unregistering graph in ROT
+static void RemoveFromRot(DWORD dwRegister)
+{
+    IRunningObjectTable *pROT;
+    if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
+	OLE_CALL_ARGS(pROT, Revoke, dwRegister);
+	OLE_RELEASE_SAFE(pROT);
+    }
+}
+
+/*
+*---------------------------------------------------------------------------------------
+*
+*  ringbuffer related methods (init, destroy)
+*
+*---------------------------------------------------------------------------------------
+*/
+/**
+ * \brief ringbuffer destroying routine
+ *
+ * \param rb pointer to empty (just allocated) ringbuffer structure
+ *
+ * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
+ */
+static void destroy_ringbuffer(grabber_ringbuffer_t * rb)
+{
+    int i;
+
+    if (!rb)
+	return;
+
+    if (rb->ringbuffer) {
+	for (i = 0; i < rb->buffersize; i++)
+	    if (rb->ringbuffer[i])
+		free(rb->ringbuffer[i]);
+	free(rb->ringbuffer);
+	rb->ringbuffer = NULL;
+    }
+    if (rb->dpts) {
+	free(rb->dpts);
+	rb->dpts = NULL;
+    }
+    if (rb->pMutex) {
+	DeleteCriticalSection(rb->pMutex);
+	free(rb->pMutex);
+	rb->pMutex = NULL;
+    }
+
+    rb->blocksize = 0;
+    rb->buffersize = 0;
+    rb->head = 0;
+    rb->tail = 0;
+    rb->count = 0;
+}
+
+/**
+ * \brief ringbuffer initialization
+ *
+ * \param rb pointer to empty (just allocated) ringbuffer structure
+ * \param buffersize size of buffer in blocks
+ * \param blocksize size of buffer's block
+ *
+ * \return S_OK if success 
+ * \return E_OUTOFMEMORY not enough memory
+ *
+ * \note routine does not allocates memory for grabber_rinbuffer_s structure
+ */
+static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize,
+			       int blocksize)
+{
+    int i;
+
+    if (!rb)
+	return E_OUTOFMEMORY;
+
+    rb->buffersize = buffersize < 2 ? 2 : buffersize;
+    rb->blocksize = blocksize;
+
+    mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Capture buffer: %d blocks of %d bytes.\n",
+	   rb->buffersize, rb->blocksize);
+
+    rb->ringbuffer = (char **) malloc(rb->buffersize * sizeof(char *));
+    if (!rb)
+	return E_POINTER;
+    memset(rb->ringbuffer, 0, rb->buffersize * sizeof(char *));
+
+    for (i = 0; i < rb->buffersize; i++) {
+	rb->ringbuffer[i] = (char *) malloc(rb->blocksize * sizeof(char));
+	if (!rb->ringbuffer[i]) {
+	    destroy_ringbuffer(rb);
+	    return E_OUTOFMEMORY;
+	}
+    }
+    rb->dpts = (double*) malloc(rb->buffersize * sizeof(double));
+    if (!rb->dpts) {
+	destroy_ringbuffer(rb);
+	return E_OUTOFMEMORY;
+    }
+    rb->head = 0;
+    rb->tail = 0;
+    rb->count = 0;
+    rb->tStart = -1;
+    rb->pMutex = (CRITICAL_SECTION *) malloc(sizeof(CRITICAL_SECTION));
+    if (!rb->pMutex) {
+	destroy_ringbuffer(rb);
+	return E_OUTOFMEMORY;
+    }
+    InitializeCriticalSection(rb->pMutex);
+    return S_OK;
+}
+
+/*
+*---------------------------------------------------------------------------------------
+*
+*  Tuner related methods (frequency, capabilities, etc
+*
+*---------------------------------------------------------------------------------------
+*/
+/**
+ * \brief returns string with name for givend PsysCon_* constant
+ *
+ * \param lPhysicalType constant from PhysicalConnectorType enumeration
+ *
+ * \return pointer to string with apropriate name
+ *
+ * \note
+ * Caller should not free returned pointer
+ */
+static char *physcon2str(const long lPhysicalType)
+{
+    int i;
+    for(i=0; tv_physcon_types[i].name; i++)
+        if(tv_physcon_types[i].type==lPhysicalType)
+            return tv_physcon_types[i].name;
+    return "Unknown";
+};
+
+/**
+ *  \brief converts MPlayer's chanlist to system country code.
+ *
+ * \param chanlist MPlayer's chanlist name
+ *
+ * \return system country code
+ *
+ * \remarks
+ * After call to IAMTVTuner::put_CountryCode with returned value tuner switches to frequency table used in specified 
+ * country (which is usually larger then MPlayer's one, so workaround will work fine).
+ *
+ * \todo
+ * Resolve trouble with cable channels (DirectShow's tuners must be switched between broadcast and cable channels modes.
+ */
+static int chanlist2country(char *chanlist)
+{
+    int i;
+    for(i=0; tv_chanlist2country[i].chanlist_name; i++)
+        if (!strcmp(chanlist, tv_chanlist2country[i].chanlist_name))
+            break;
+    return tv_chanlist2country[i].country_code;
+}
+
+/**
+ * \brief loads specified resource from module and return pointer to it
+ *
+ * \param hDLL valid module desriptor
+ * \param index index of resource. resource with name "#<index>" will be loaded
+ *
+ * \return pointer to loader resource or NULL if error occured
+ */
+static void *GetRC(HMODULE hDLL, int index)
+{
+    char szRCDATA[10];
+    char szName[10];
+    HRSRC hRes;
+    HGLOBAL hTable;
+
+    snprintf(szRCDATA, 10, "#%d", (int)RT_RCDATA);
+    snprintf(szName, 10, "#%d", index);
+
+    hRes = FindResource(hDLL, szName, szRCDATA);
+    if (!hRes) {
+	return NULL;
+    }
+    hTable = LoadResource(hDLL, hRes);
+    if (!hTable) {
+	return NULL;
+    }
+    return LockResource(hTable);
+}
+
+/**
+ * \brief loads frequency table for given country from kstvtune.ax
+ *
+ * \param[in] nCountry - country code
+ * \param[in] nInputType (TunerInputCable or TunerInputAntenna)
+ * \param[out] pplFreqTable - address of variable that receives pointer to array, containing frequencies
+ * \param[out] pnLen length of array 
+ * \param[out] pnFirst - channel number of first entry in array (nChannelMax)
+ *
+ * \return S_OK if success
+ * \return E_POINTER pplFreqTable==NULL || plFirst==NULL || pnLen==NULL
+ * \return E_FAIL error occured during load
+ *
+ * \remarks 
+ * - array must be freed by caller
+ * - MSDN says that it is not neccessery to unlock or free resource. It will be done after unloading DLL
+ */
+static HRESULT load_freq_table(int nCountry, int nInputType,
+			       long **pplFreqTable, int *pnLen,
+			       int *pnFirst)
+{
+    HMODULE hDLL;
+    long *plFreqTable;
+    TRCCountryList *pCountryList;
+    int i, index;
+
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: load_freq_table called %d (%d)\n",nCountry,nInputType);
+    /* ASSERT(sizeof(TRCCountryList)==10); // need properly aligned structure */
+
+    if (!pplFreqTable || !pnFirst || !pnLen)
+	return E_POINTER;
+    if (!nCountry)
+	return E_FAIL;
+
+    hDLL = LoadLibrary("kstvtune.ax");
+    if (!hDLL) {
+	return E_FAIL;
+    }
+    pCountryList = GetRC(hDLL, 9999);
+    if (!pCountryList) {
+	FreeLibrary(hDLL);
+	return E_FAIL;
+    }
+    for (i = 0; pCountryList[i].CountryCode != 0; i++)
+	if (pCountryList[i].CountryCode == nCountry)
+	    break;
+    if (pCountryList[i].CountryCode == 0) {
+	FreeLibrary(hDLL);
+	return E_FAIL;
+    }
+    if (nInputType == TunerInputCable)
+	index = pCountryList[i].CableFreqTable;
+    else
+	index = pCountryList[i].BroadcastFreqTable;
+
+    plFreqTable = GetRC(hDLL, index);	//First element is number of first channel, second - number of last channel
+    if (!plFreqTable) {
+	FreeLibrary(hDLL);
+	return E_FAIL;
+    }
+    *pnFirst = plFreqTable[0];
+    *pnLen = (int) (plFreqTable[1] - plFreqTable[0] + 1);
+    *pplFreqTable = (long *) malloc((*pnLen) * sizeof(long));
+    if (!*pplFreqTable) {
+	FreeLibrary(hDLL);
+	return E_FAIL;
+    }
+    for (i = 0; i < *pnLen; i++) {
+	(*pplFreqTable)[i] = plFreqTable[i + 2];
+    }
+    FreeLibrary(hDLL);
+    return S_OK;
+}
+
+/**
+ * \brief tunes to given frequency through IKsPropertySet call
+ *
+ * \param pTVTuner IAMTVTuner interface of capture device
+ * \param lFreq frequency to tune (in Hz)
+ *
+ * \return S_OK success
+ * \return apropriate error code otherwise
+ *
+ * \note
+ * Due to either bug in driver or error in following code calll to IKsProperty::Set 
+ * in this methods always fail with error 0x8007007a.
+ *
+ * \todo test code on other machines and an error
+ */
+static HRESULT set_frequency_direct(IAMTVTuner * pTVTuner, long lFreq)
+{
+    HRESULT hr;
+    DWORD dwSupported = 0;
+    DWORD cbBytes = 0;
+    KSPROPERTY_TUNER_MODE_CAPS_S mode_caps;
+    KSPROPERTY_TUNER_FREQUENCY_S frequency;
+    IKsPropertySet *pKSProp;
+
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency_direct called\n");
+
+    memset(&mode_caps, 0, sizeof(mode_caps));
+    memset(&frequency, 0, sizeof(frequency));
+
+    hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp);
+    if (FAILED(hr))
+	return hr;		//no IKsPropertySet interface
+
+    mode_caps.Mode = AMTUNER_MODE_TV;
+    hr = OLE_CALL_ARGS(pKSProp, QuerySupported, &PROPSETID_TUNER,
+		   KSPROPERTY_TUNER_MODE_CAPS, &dwSupported);
+    if (FAILED(hr)) {
+	OLE_RELEASE_SAFE(pKSProp);
+	return hr;
+    }
+
+    if (!dwSupported & KSPROPERTY_SUPPORT_GET) {
+	OLE_RELEASE_SAFE(pKSProp);
+	return E_FAIL;		//PROPSETID_TINER not supported
+    }
+
+    hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER,
+		   KSPROPERTY_TUNER_MODE_CAPS,
+		   INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps),
+		   INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps),
+		   &mode_caps, sizeof(mode_caps), &cbBytes);
+
+    frequency.Frequency = lFreq;
+
+    if (mode_caps.Strategy == KS_TUNER_STRATEGY_DRIVER_TUNES)
+	frequency.TuningFlags = KS_TUNER_TUNING_FINE;
+    else
+	frequency.TuningFlags = KS_TUNER_TUNING_EXACT;
+
+    if (lFreq < mode_caps.MinFrequency || lFreq > mode_caps.MaxFrequency) {
+	OLE_RELEASE_SAFE(pKSProp);
+	return E_FAIL;
+    }
+
+    hr = OLE_CALL_ARGS(pKSProp, Set, &PROPSETID_TUNER,
+		   KSPROPERTY_TUNER_FREQUENCY,
+		   INSTANCEDATA_OF_PROPERTY_PTR(&frequency),
+		   INSTANCEDATA_OF_PROPERTY_SIZE(frequency),
+		   &frequency, sizeof(frequency));
+    if (FAILED(hr)) {
+	OLE_RELEASE_SAFE(pKSProp);
+	return hr;
+    }
+
+    OLE_RELEASE_SAFE(pKSProp);
+
+    return S_OK;
+}
+
+/**
+ * \brief find channel with nearest frequency and set it
+ *
+ * \param priv driver's private data
+ * \param lFreq frequency in Hz
+ *
+ * \return S_OK if success
+ * \return E_FAIL if error occured
+ */
+static HRESULT set_nearest_freq(priv_t * priv, long lFreq)
+{
+    HRESULT hr;
+    int i;
+    long lFreqDiff=-1;
+    int nChannel;
+    TunerInputType tunerInput;
+    long lInput;
+
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_nearest_freq called\n");
+    if(priv->freq_table_len == -1 && !priv->freq_table) {
+
+        hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput);
+        if(FAILED(hr)){ //Falling back to 0
+            lInput=0;
+        }
+
+        hr = OLE_CALL_ARGS(priv->pTVTuner, get_InputType, lInput, &tunerInput);
+
+        if (load_freq_table(chanlist2country(priv->tv_param->chanlist), tunerInput, &(priv->freq_table), &(priv->freq_table_len), &(priv->first_channel)) != S_OK) {//FIXME
+            priv->freq_table_len=0;
+            priv->freq_table=NULL;
+            mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableExtractFreqTable);
+            return E_FAIL;
+        };
+        mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_FreqTableLoaded, tunerInput == TunerInputAntenna ? "broadcast" : "cable",
+            chanlist2country(priv->tv_param->chanlist), priv->freq_table_len);
+    }
+
+    if (priv->freq_table_len <= 0)
+	return E_FAIL;
+
+    //FIXME: rewrite search algo
+    nChannel = -1;
+    for (i = 0; i < priv->freq_table_len; i++) {
+	if (nChannel == -1 || labs(lFreq - priv->freq_table[i]) < lFreqDiff) {
+	    nChannel = priv->first_channel + i;
+	    lFreqDiff = labs(lFreq - priv->freq_table[i]);
+	}
+    }
+    if (nChannel == -1) {
+	mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableFindNearestChannel);
+	return E_FAIL;
+    }
+    hr = OLE_CALL_ARGS(priv->pTVTuner, put_Channel, nChannel,
+		   AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT);
+    if (FAILED(hr)) {
+	mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableToSetChannel, (unsigned int)hr);
+	return E_FAIL;
+    }
+    return S_OK;
+}
+
+/**
+ * \brief setting frequency. decides whether use direct call/workaround
+ *
+ * \param priv driver's private data
+ * \param lFreq frequency in Hz
+ *
+ * \return TVI_CONTROL_TRUE if success
+ * \return TVI_CONTROL_FALSE if error occured
+ *
+ * \todo check for freq boundary
+ */
+static int set_frequency(priv_t * priv, long lFreq)
+{
+    HRESULT hr;
+
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency called\n");
+    if (!priv->pTVTuner)
+	return TVI_CONTROL_FALSE;
+    if (priv->direct_setfreq_call) {	//using direct call to set frequency
+	hr = set_frequency_direct(priv->pTVTuner, lFreq);
+	if (FAILED(hr)) {
+	    mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_DirectSetFreqFailed);
+	    priv->direct_setfreq_call = 0;
+	}
+    }
+    if (!priv->direct_setfreq_call) {
+	hr = set_nearest_freq(priv, lFreq);
+    }
+    if (FAILED(hr))
+	return TVI_CONTROL_FALSE;
+#ifdef DEPRECATED
+    priv->pGrabber->ClearBuffer(priv->pGrabber);
+#endif
+    return TVI_CONTROL_TRUE;
+}
+
+/**
+ * \brief return current frequency  from tuner (in Hz)
+ *
+ * \param pTVTuner IAMTVTuner interface of tuner
+ * \param plFreq address of variable that receives current frequency
+ *
+ * \return S_OK success
+ * \return E_POINTER pTVTuner==NULL || plFreq==NULL
+ * \return apropriate error code otherwise
+ */
+static HRESULT get_frequency_direct(IAMTVTuner * pTVTuner, long *plFreq)
+{
+    HRESULT hr;
+    KSPROPERTY_TUNER_STATUS_S TunerStatus;
+    DWORD cbBytes;
+    IKsPropertySet *pKSProp;
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency_direct called\n");
+
+    if (!plFreq)
+	return E_POINTER;
+
+    hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp);
+    if (FAILED(hr)) {
+	mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq QueryInterface failed\n");
+	return hr;
+    }
+
+    hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER,
+		   KSPROPERTY_TUNER_STATUS,
+		   INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus),
+		   INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus),
+		   &TunerStatus, sizeof(TunerStatus), &cbBytes);
+    if (FAILED(hr)) {
+	mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq Get failure\n");
+	return hr;
+    }
+    *plFreq = TunerStatus.CurrentFrequency;
+    return S_OK;
+}
+
+/**
+ * \brief gets current frequency 
+ *
+ * \param priv driver's private data structure 
+ * \param plFreq - pointer to long int to store frequency to (in Hz)
+ *
+ * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise
+ */
+static int get_frequency(priv_t * priv, long *plFreq)
+{
+    HRESULT hr;
+
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency called\n");
+
+    if (!plFreq || !priv->pTVTuner)
+	return TVI_CONTROL_FALSE;
+
+    if (priv->direct_getfreq_call) {	//using direct call to get frequency
+	hr = get_frequency_direct(priv->pTVTuner, plFreq);
+	if (FAILED(hr)) {
+	    mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_DirectGetFreqFailed);
+	    priv->direct_getfreq_call = 0;
+	}
+    }
+    if (!priv->direct_getfreq_call) {
+        hr=OLE_CALL_ARGS(priv->pTVTuner, get_VideoFrequency, plFreq);
+	if (FAILED(hr))
+	    return TVI_CONTROL_FALSE;
+
+    }
+    return TVI_CONTROL_TRUE;
+}
+
+/**
+ * \brief get tuner capabilities
+ *
+ * \param priv driver's private data
+ */
+static void get_capabilities(priv_t * priv)
+{
+    long lAvailableFormats;
+    HRESULT hr;
+    int i;
+    long lInputPins, lOutputPins, lRelated, lPhysicalType;
+    IEnumPins *pEnum;
+    char tmp[200];
+    IPin *pPin = 0;
+    PIN_DIRECTION ThisPinDir;
+    PIN_INFO pi;
+    IAMAudioInputMixer *pIAMixer;
+
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_capabilities called\n");
+    if (priv->pTVTuner) {
+
+	mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_SupportedNorms);
+	hr = OLE_CALL_ARGS(priv->pTVTuner, get_AvailableTVFormats,
+		       &lAvailableFormats);
+	if (FAILED(hr))
+	    tv_available_norms_count = 0;
+	else {
+	    for (i = 0; i < TV_NORMS_COUNT; i++) {
+		if (lAvailableFormats & tv_norms[i].index) {
+		    tv_available_norms[tv_available_norms_count] = i;
+		    mp_msg(MSGT_TV, MSGL_V, " %d=%s;",
+			   tv_available_norms_count + 1, tv_norms[i].name);
+		    tv_available_norms_count++;
+		}
+	    }
+	}
+	mp_msg(MSGT_TV, MSGL_INFO, "\n");
+    }
+    if (priv->pCrossbar) {
+	OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins,
+		  &lInputPins);
+
+	tv_available_inputs = (long *) malloc(sizeof(long) * lInputPins);
+	tv_available_inputs_count = 0;
+
+	mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_AvailableVideoInputs);
+	for (i = 0; i < lInputPins; i++) {
+	    OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1, i,
+		      &lRelated, &lPhysicalType);
+
+	    if (lPhysicalType < 0x1000) {
+		tv_available_inputs[tv_available_inputs_count++] = i;
+		mp_msg(MSGT_TV, MSGL_V, " %d=%s;",
+		       tv_available_inputs_count - 1,
+		       physcon2str(lPhysicalType));
+	    }
+	}
+	mp_msg(MSGT_TV, MSGL_INFO, "\n");
+
+	set_crossbar_input(priv, 0);
+    }
+
+    if (priv->adev_index != -1) {
+	hr = OLE_CALL_ARGS(priv->pAudioFilter, EnumPins, &pEnum);
+	if (FAILED(hr))
+	    return;
+	mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_AvailableAudioInputs);
+	i = 0;
+	while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) {
+	    memset(&pi, 0, sizeof(pi));
+	    memset(tmp, 0, 200);
+	    OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir);
+	    if (ThisPinDir == PINDIR_INPUT) {
+		OLE_CALL_ARGS(pPin, QueryPinInfo, &pi);
+		wtoa(pi.achName, tmp, 200);
+		OLE_RELEASE_SAFE(pi.pFilter);
+		mp_msg(MSGT_TV, MSGL_V, " %d=%s", i, tmp);
+		mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin);
+		hr = OLE_QUERYINTERFACE(pPin, IID_IAMAudioInputMixer,pIAMixer);
+		if (SUCCEEDED(hr)) {
+		    if (i == priv->tv_param->audio_id) {
+			OLE_CALL_ARGS(pIAMixer, put_Enable, TRUE);
+                        if(priv->tv_param->volume>0)
+			    OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.01 * priv->tv_param->volume);
+#if 0
+                        else
+			    OLE_CALL_ARGS(pIAMixer, put_MixLevel, 1.0);
+#endif
+			mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_InputSelected);
+		    } else {
+			OLE_CALL_ARGS(pIAMixer, put_Enable, FALSE);
+#if 0
+			OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.0);
+#endif
+		    }
+		    OLE_RELEASE_SAFE(pIAMixer);
+		}
+		mp_msg(MSGT_TV, MSGL_V, ";");
+		OLE_RELEASE_SAFE(pPin);
+		i++;
+	    }
+	}
+	mp_msg(MSGT_TV, MSGL_INFO, "\n");
+	OLE_RELEASE_SAFE(pEnum);
+    }
+}
+
+/*
+*---------------------------------------------------------------------------------------
+*
+*  Filter related methods
+*
+*---------------------------------------------------------------------------------------
+*/
+/**
+ * \brief building in graph audio/video capture chain
+ *
+ * \param priv           driver's private data
+ * \param pCaptureFilter pointer to capture device's IBaseFilter interface
+ * \param pbuf           ringbuffer data structure
+ * \param pmt            media type for chain (AM_MEDIA_TYPE)
+ *
+ * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
+ */
+static HRESULT build_sub_graph(priv_t * priv, IBaseFilter * pCaptureFilter,
+			       grabber_ringbuffer_t * pbuf,
+			       AM_MEDIA_TYPE * pmt, const GUID* ppin_category)
+{
+    HRESULT hr;
+
+    IPin *pSGIn;
+    IPin *pSGOut;
+    IPin *pNRIn=NULL;
+    IPin *pCapturePin;
+
+    IBaseFilter *pNR = NULL;
+    IBaseFilter *pSGF = NULL;
+
+    ISampleGrabber *pSG = NULL;
+
+    hr=S_OK;
+    do{
+        hr = OLE_CALL_ARGS(priv->pBuilder, FindPin,
+    		   (IUnknown *) pCaptureFilter,
+    		   PINDIR_OUTPUT, ppin_category,
+    		   &(pmt->majortype), FALSE, 0, &pCapturePin);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+        /* Addinf SampleGrabber filter for video stream */
+        hr = CoCreateInstance((GUID *) & CLSID_SampleGrabber, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &pSGF);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+        hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, pSGF, L"Sample Grabber");
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+        hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pSGF,PINDIR_INPUT, NULL, NULL, FALSE, 0, &pSGIn);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+        hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pSGF,PINDIR_OUTPUT, NULL, NULL, FALSE, 0, &pSGOut);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+
+        /* creating ringbuffer for video samples */
+        priv->pCSGCB = CSampleGrabberCB_Create(pbuf);
+        if(!priv->pCSGCB){
+            mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY);
+            break;
+        }
+
+        /* initializing SampleGrabber filter */
+        hr = OLE_QUERYINTERFACE(pSGF, IID_ISampleGrabber, pSG);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+        hr = OLE_CALL_ARGS(pSG, SetMediaType, pmt);	//set desired mediatype
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+    //    hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1);	//we want to receive copy of sample's data
+        hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) priv->pCSGCB, 0);	//we want to receive sample
+
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+        hr = OLE_CALL_ARGS(pSG, SetOneShot, FALSE);	//... for all frames
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+        hr = OLE_CALL_ARGS(pSG, SetBufferSamples, FALSE);	//... do not buffer samples in sample grabber
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+        OLE_RELEASE_SAFE(pSG);
+
+        if(priv->tv_param->normalize_audio_chunks && !memcmp(&(pmt->majortype),&(MEDIATYPE_Audio),16)){
+            set_buffer_preference(20,(WAVEFORMATEX*)(pmt->pbFormat),pCapturePin,pSGIn);
+    }
+
+        /* connecting filters together: VideoCapture --> SampleGrabber */
+        hr = OLE_CALL_ARGS(priv->pGraph, Connect, pCapturePin, pSGIn);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+
+        if(priv->tv_param->hidden_video_renderer){
+            IEnumFilters* pEnum;
+            IBaseFilter* pFilter;
+
+            hr=OLE_CALL_ARGS(priv->pBuilder,RenderStream,NULL,NULL,(IUnknown*)pCapturePin,NULL,NULL);
+
+            OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum);
+            while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) {
+                LPVIDEOWINDOW pVideoWindow;
+                hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow);
+                if (SUCCEEDED(hr))
+                {
+                    OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0);
+                    OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0);
+                    OLE_RELEASE_SAFE(pVideoWindow);
+                }
+                OLE_RELEASE_SAFE(pFilter);
+            }
+            OLE_RELEASE_SAFE(pEnum);
+        }else
+        {
+            /* adding sink for video stream */
+            hr = CoCreateInstance((GUID *) & CLSID_NullRenderer, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &pNR);
+            if(FAILED(hr)){
+                mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr);
+                break;
+            }
+            hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, pNR, L"Null Renderer");
+            if(FAILED(hr)){
+                mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr);
+                break;
+            }
+            hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pNR,PINDIR_INPUT, NULL, NULL, FALSE, 0, &pNRIn);
+            if(FAILED(hr)){
+                mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr);
+                break;
+            }
+            /*
+               Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection
+            */
+            if(memcmp(&(pmt->majortype),&MEDIATYPE_VBI,16)){
+                /* connecting filters together: SampleGrabber --> NullRenderer */
+                hr = OLE_CALL_ARGS(priv->pGraph, Connect, pSGOut, pNRIn);
+                if(FAILED(hr)){
+                    mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr);
+                    break;
+                }
+            }
+        }
+
+        hr = S_OK;
+    } while(0);
+    OLE_RELEASE_SAFE(pSGF);
+    OLE_RELEASE_SAFE(pSGIn);
+    OLE_RELEASE_SAFE(pSGOut);
+    OLE_RELEASE_SAFE(pNR);
+    OLE_RELEASE_SAFE(pNRIn);
+    OLE_RELEASE_SAFE(pCapturePin);
+
+    return hr;
+}
+
+/**
+ * \brief configures crossbar for grabbing video stream from given input
+ *
+ * \param priv driver's private data
+ * \param input index of available video input to get data from
+ *
+ * \return TVI_CONTROL_TRUE success
+ * \return TVI_CONTROL_FALSE error
+ */
+static int set_crossbar_input(priv_t * priv, int input)
+{
+    HRESULT hr;
+    int i, nVideoDecoder, nAudioDecoder;
+    long lInput, lInputRelated, lRelated, lPhysicalType, lOutputPins,
+	lInputPins;
+
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Configuring crossbar\n");
+    if (!priv->pCrossbar || input < 0
+	|| input >= tv_available_inputs_count)
+	return TVI_CONTROL_FALSE;
+
+    OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins, &lInputPins);
+
+    lInput = tv_available_inputs[input];
+
+    if (lInput < 0 || lInput >= lInputPins)
+	return TVI_CONTROL_FALSE;
+
+    OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1 /* input */ , lInput,
+	      &lInputRelated, &lPhysicalType);
+
+    nVideoDecoder = nAudioDecoder = -1;
+    for (i = 0; i < lOutputPins; i++) {
+	OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 0 /*output */ , i,
+		  &lRelated, &lPhysicalType);
+	if (lPhysicalType == PhysConn_Video_VideoDecoder)
+	    nVideoDecoder = i;
+	if (lPhysicalType == PhysConn_Audio_AudioDecoder)
+	    nAudioDecoder = i;
+    }
+    if (nVideoDecoder >= 0) {
+	//connecting given input with video decoder
+	hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nVideoDecoder, lInput);
+	if (hr != S_OK) {
+	    mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableConnectInputVideoDecoder, (unsigned int)hr);
+	    return TVI_CONTROL_FALSE;
+	}
+    }
+    if (nAudioDecoder >= 0 && lInputRelated >= 0) {
+	hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nAudioDecoder,
+		       lInputRelated);
+	if (hr != S_OK) {
+	    mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableConnectInputAudioDecoder, (unsigned int)hr);
+	    return TVI_CONTROL_FALSE;
+	}
+    }
+    return TVI_CONTROL_TRUE;
+}
+
+/**
+ * \brief adjusts video control (hue,saturation,contrast,brightess)
+ *
+ * \param priv driver's private data
+ * \param control which control to adjust
+ * \param value new value for control (0-100)
+ *
+ * \return TVI_CONTROL_TRUE success
+ * \return TVI_CONTROL_FALSE error
+ */
+static int set_control(priv_t * priv, int control, int value)
+{
+    long lMin, lMax, lStepping, lDefault, lFlags, lValue;
+    HRESULT hr;
+
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_control called\n");
+    if (value < -100 || value > 100 || !priv->pVideoProcAmp)
+	return TVI_CONTROL_FALSE;
+
+    hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control,
+		   &lMin, &lMax, &lStepping, &lDefault, &lFlags);
+    if (FAILED(hr) || lFlags != VideoProcAmp_Flags_Manual)
+	return TVI_CONTROL_FALSE;
+
+    lValue = lMin + (value + 100) * (lMax - lMin) / 200;
+    /*
+       Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256
+     */
+    if (lStepping > lMax) {
+	mp_msg(MSGT_TV, MSGL_DBG3,
+	       "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n",
+	       lStepping, lMax,control);
+	lStepping = 1;
+    }
+    lValue -= lValue % lStepping;
+    hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Set, control, lValue,
+		   VideoProcAmp_Flags_Manual);
+    if (FAILED(hr))
+	return TVI_CONTROL_FALSE;
+
+    return TVI_CONTROL_TRUE;
+}
+
+/**
+ * \brief get current value of video control (hue,saturation,contrast,brightess)
+ *
+ * \param priv driver's private data
+ * \param control which control to adjust
+ * \param pvalue address of variable thar receives current value
+ *
+ * \return TVI_CONTROL_TRUE success
+ * \return TVI_CONTROL_FALSE error
+ */
+static int get_control(priv_t * priv, int control, int *pvalue)
+{
+    long lMin, lMax, lStepping, lDefault, lFlags, lValue;
+    HRESULT hr;
+
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_control called\n");
+    if (!pvalue || !priv->pVideoProcAmp)
+	return TVI_CONTROL_FALSE;
+
+    hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control,
+		   &lMin, &lMax, &lStepping, &lDefault, &lFlags);
+    if (FAILED(hr))
+	return TVI_CONTROL_FALSE;
+    if (lMin == lMax) {
+	*pvalue = lMin;
+	return TVI_CONTROL_TRUE;
+    }
+
+    hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Get, control, &lValue, &lFlags);
+    if (FAILED(hr))
+	return TVI_CONTROL_FALSE;
+
+    *pvalue = 200 * (lValue - lMin) / (lMax - lMin) - 100;
+
+    return TVI_CONTROL_TRUE;
+}
+
+/**
+ * \brief extracts fcc,width,height from AM_MEDIA_TYPE
+ *
+ * \param pmt pointer to AM_MEDIA_TYPE to extract data from
+ * \param pfcc address of variable that receives FourCC
+ * \param pwidth address of variable that receives width
+ * \param pheight address of variable that recevies height
+ *
+ * \return 1 if data extracted successfully, 0 - otherwise
+ */
+static int extract_video_format(AM_MEDIA_TYPE * pmt, int *pfcc,
+				int *pwidth, int *pheight)
+{
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_video_format called\n");
+    if (!pmt)
+	return 0;
+    if (!pmt->pbFormat)
+	return 0;
+    if (memcmp(&(pmt->formattype), &FORMAT_VideoInfo, 16) != 0)
+	return 0;
+    if (pfcc)
+	*pfcc = subtype2imgfmt(&(pmt->subtype));
+    if (pwidth)
+	*pwidth = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biWidth;
+    if (pheight)
+	*pheight = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biHeight;
+    return 1;
+}
+
+/**
+ * \brief extracts samplerate,bits,channels from AM_MEDIA_TYPE
+ *
+ * \param pmt pointer to AM_MEDIA_TYPE to extract data from
+ * \param pfcc address of variable that receives samplerate
+ * \param pwidth address of variable that receives number of bits per sample
+ * \param pheight address of variable that recevies number of channels
+ *
+ * \return 1 if data extracted successfully, 0 - otherwise
+ */
+static int extract_audio_format(AM_MEDIA_TYPE * pmt, int *psamplerate,
+				int *pbits, int *pchannels)
+{
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_audio_format called\n");
+    if (!pmt)
+	return 0;
+    if (!pmt->pbFormat)
+	return 0;
+    if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0)
+	return 0;
+    if (psamplerate)
+	*psamplerate = ((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec;
+    if (pbits)
+	*pbits = ((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample;
+    if (pchannels)
+	*pchannels = ((WAVEFORMATEX *) pmt->pbFormat)->nChannels;
+    return 1;
+}
+
+/**
+ * \brief checks if AM_MEDIA_TYPE compatible with given samplerate,bits,channels
+ *
+ * \param pmt pointer to AM_MEDIA_TYPE for check
+ * \param samplerate audio samplerate
+ * \param bits bits per sample
+ * \param channels number of audio channels
+ *
+ * \return 1 if AM_MEDIA_TYPE compatible
+ * \return 0 if not
+ */
+static int check_audio_format(AM_MEDIA_TYPE * pmt, int samplerate,
+			      int bits, int channels)
+{
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_audio_format called\n");
+    if (!pmt)
+	return 0;
+    if (memcmp(&(pmt->majortype), &MEDIATYPE_Audio, 16) != 0)
+	return 0;
+    if (memcmp(&(pmt->subtype), &MEDIASUBTYPE_PCM, 16) != 0)
+	return 0;
+    if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0)
+	return 0;
+    if (!pmt->pbFormat)
+	return 0;
+    if (((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec != samplerate)
+	return 0;
+    if (((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample != bits)
+	return 0;
+    if (channels > 0
+	&& ((WAVEFORMATEX *) pmt->pbFormat)->nChannels != channels)
+	return 0;
+
+    return 1;
+}
+
+/**
+ * \brief checks if AM_MEDIA_TYPE compatible with given fcc,width,height
+ *
+ * \param pmt pointer to AM_MEDIA_TYPE for check
+ * \param fcc FourCC (compression)
+ * \param width width of picture
+ * \param height height of picture
+ *
+ * \return 1 if AM_MEDIA_TYPE compatible
+ & \return 0 if not
+ *
+ * \note 
+ * width and height are currently not used
+ *
+ * \todo 
+ * add width/height check
+ */
+static int check_video_format(AM_MEDIA_TYPE * pmt, int fcc, int width,
+			      int height)
+{
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_video_format called\n");
+    if (!pmt)
+	return 0;
+    if (memcmp(&(pmt->majortype), &MEDIATYPE_Video, 16) != 0)
+	return 0;
+    if (subtype2imgfmt(&(pmt->subtype)) != fcc)
+	return 0;
+    return 1;
+}
+
+/**
+ * \brief converts DirectShow subtype to MPlayer's IMGFMT
+ *
+ * \param subtype DirectShow subtype for video format
+ *
+ * \return MPlayer's IMGFMT or 0 if error occured
+ */
+static int subtype2imgfmt(const GUID * subtype)
+{
+    int i;
+    for (i = 0; img_fmt_list[i].fmt; i++) {
+	if (memcmp(subtype, img_fmt_list[i].subtype, 16) == 0)
+	    return img_fmt_list[i].fmt;
+    }
+    return 0;
+}
+
+/**
+ * \brief prints filter name and it pins
+ *
+ * \param pFilter - IBaseFilter to get data from
+ *
+ * \return S_OK if success, error code otherwise
+ */
+static HRESULT show_filter_info(IBaseFilter * pFilter)
+{
+    char tmp[200];
+    FILTER_INFO fi;
+    LPENUMPINS pEnum = 0;
+    IPin *pPin = 0;
+    PIN_DIRECTION ThisPinDir;
+    PIN_INFO pi;
+    HRESULT hr;
+    int i;
+
+    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: show_filter_info called\n");
+    memset(&fi, 0, sizeof(fi));
+    memset(tmp, 0, 200);
+
+    OLE_CALL_ARGS(pFilter, QueryFilterInfo, &fi);
+    OLE_RELEASE_SAFE(fi.pGraph);
+    wtoa(fi.achName, tmp, 200);
+    mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p output pins:",
+	   pFilter, tmp, fi.pGraph);
+    hr = OLE_CALL_ARGS(pFilter, EnumPins, &pEnum);
+    if (FAILED(hr))
+	return hr;
+    i = 0;
+    while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) {
+	memset(&pi, 0, sizeof(pi));
+	memset(tmp, 0, 200);
+	OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir);
+	if (ThisPinDir == PINDIR_OUTPUT) {
+	    OLE_CALL_ARGS(pPin, QueryPinInfo, &pi);
+	    wtoa(pi.achName, tmp, 200);
+	    OLE_RELEASE_SAFE(pi.pFilter);
+	    mp_msg(MSGT_TV, MSGL_DBG2, " %d=%s", i, tmp);
+	    mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin);
+	    mp_msg(MSGT_TV, MSGL_DBG2, ";");
+	    OLE_RELEASE_SAFE(pPin);
+	    i++;
+	}
+    }
+    mp_msg(MSGT_TV, MSGL_DBG2, "\n");
+    OLE_RELEASE_SAFE(pEnum);
+    return S_OK;
+}
+
+/**
+ * \brief gets device's frendly in ANSI encoding
+ *
+ * \param pM IMoniker interface, got in enumeration process
+ * \param category device category 
+ *
+ * \return TVI_CONTROL_TRUE if operation succeded, TVI_CONTROL_FALSE - otherwise
+ */
+static int get_device_name(IMoniker * pM, char *pBuf, int nLen)
+{
+    HRESULT hr;
+    VARIANT var;
+    IPropertyBag *pPropBag;
+    hr = OLE_CALL_ARGS(pM, BindToStorage, 0, 0, &IID_IPropertyBag,(void *) &pPropBag);
+    if (FAILED(hr)) {
+	mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Call to BindToStorage failed\n");
+	return TVI_CONTROL_FALSE;
+    }
+    var.vt = VT_BSTR;
+    hr = OLE_CALL_ARGS(pPropBag, Read, L"Description", (LPVARIANT) & var,
+		   NULL);
+    if (FAILED(hr)) {
+	hr = OLE_CALL_ARGS(pPropBag, Read, L"FriendlyName", (LPVARIANT) & var,
+		       NULL);
+    }
+    OLE_RELEASE_SAFE(pPropBag);
+    if (SUCCEEDED(hr)) {
+	wtoa(var.bstrVal, pBuf, nLen);
+        return TVI_CONTROL_TRUE;
+    }
+    return TVI_CONTROL_FALSE;
+}
+
+/**
+ * \brief find capture device at given index
+ *
+ * \param index device index to search for (-1 mean only print available)
+ * \param category device category 
+ *
+ * \return IBaseFilter interface for capture device with given index
+ * 
+ * Sample values for category:
+ *  CLSID_VideoInputDeviceCategory - Video Capture Sources
+ *  CLSID_AudioInputDeviceCategory - Audio Capture Sources
+ * See DirectShow SDK documentation for other possible values
+ */
+static IBaseFilter *find_capture_device(int index, REFCLSID category)
+{
+    IBaseFilter *pFilter = NULL;
+    ICreateDevEnum *pDevEnum = NULL;
+    IEnumMoniker *pClassEnum = NULL;
+    IMoniker *pM;
+    HRESULT hr;
+    ULONG cFetched;
+    int i;
+    char tmp[DEVICE_NAME_MAX_LEN + 1];
+    hr = CoCreateInstance((GUID *) & CLSID_SystemDeviceEnum, NULL,
+			  CLSCTX_INPROC_SERVER, &IID_ICreateDevEnum,
+			  (void *) &pDevEnum);
+    if (FAILED(hr)) {
+	mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create device enumerator\n");
+	return NULL;
+    }
+
+    hr = OLE_CALL_ARGS(pDevEnum, CreateClassEnumerator, category, &pClassEnum, 0);
+    OLE_RELEASE_SAFE(pDevEnum);
+    if (FAILED(hr)) {
+	mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create class enumerator\n");
+	return NULL;
+    }
+    if (hr == S_FALSE) {
+	mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: No capture devices found\n");
+	return NULL;
+    }
+
+    OLE_CALL(pClassEnum,Reset);
+    for (i = 0; OLE_CALL_ARGS(pClassEnum, Next, 1, &pM, &cFetched) == S_OK; i++) {
+	if(get_device_name(pM, tmp, DEVICE_NAME_MAX_LEN)!=TVI_CONTROL_TRUE)
+	    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableGetDeviceName, i);
+        else
+	    mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_DeviceName, i, tmp);
+	if (index != -1 && i == index) {
+	    mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_UsingDevice, index, tmp);
+	    hr = OLE_CALL_ARGS(pM, BindToObject, 0, 0, &IID_IBaseFilter,(void *) &pFilter);
+	    if (FAILED(hr))
+		pFilter = NULL;
+	}
+	OLE_RELEASE_SAFE(pM);
+    }
+    if (index != -1 && !pFilter) {
+	mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_DeviceNotFound,
+	       index);
+    }
+    OLE_RELEASE_SAFE(pClassEnum);
+
+    return pFilter;
+}
+
+/**
+ * \brief get array of available formats through call to IAMStreamConfig::GetStreamCaps
+ * 
+ * \param[in] pVideoStreamConfig  IAMStreamConfig of used capture device's output pin
+ * \param[in] pMediaType  MEDIATYPE_Video or MEDIATYPE_Audio
+ * \param[out] parpmtMedia  address of variable that receives pointer to array of AM_MEDIA_TYPE structures
+ * \param[out] parCaps address of variable thar receives pointer to array of VIDEOSTREAM_CONFIG_CAPS or AUDIO_STREAM_CONFIG_CAPS
+ *
+ * \return S_OK success
+ * \return E_POINTER one of parameters is NULL
+ * \return E_FAIL required size of buffer is unknown for given media type
+ * \return E_OUTOFMEMORY not enough memory
+ * \return other error code from called methods
+ *
+ * \remarks
+ * last item or returned arrays will be NULL
+ */
+static HRESULT get_available_formats_stream(IAMStreamConfig *
+					    pStreamConfig,
+					    const GUID * pMediaType,
+					    AM_MEDIA_TYPE *** parpmtMedia,
+					    void ***parCaps)
+{
+    AM_MEDIA_TYPE **arpmt;
+    void **pBuf=NULL;
+
+    HRESULT hr;
+    int i, count, size;
+    int done;
+
+    mp_msg(MSGT_TV, MSGL_DBG4,
+	   "tvi_dshow: get_available_formats_stream called\n");
+
+    if (!pStreamConfig || !pMediaType || !parpmtMedia || !parCaps)
+	return E_POINTER;
+
+    hr=OLE_CALL_ARGS(pStreamConfig, GetNumberOfCapabilities, &count, &size);
+    if (FAILED(hr)) {
+	mp_msg(MSGT_TV, MSGL_DBG4,
+	       "tvi_dshow: Call to GetNumberOfCapabilities failed (get_available_formats_stream)\n");
+	return hr;
+    }
+    if (memcmp(pMediaType, &MEDIATYPE_Video, 16) == 0){
+	if (size != sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
+	    mp_msg(MSGT_TV, MSGL_DBG4,
+		   "tvi_dshow: Wrong video structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
+	    return E_FAIL;
+	} else if (memcmp(pMediaType, &MEDIATYPE_Audio, 16) == 0){
+	    if (size != sizeof(AUDIO_STREAM_CONFIG_CAPS)) {
+		mp_msg(MSGT_TV, MSGL_DBG4,
+		       "tvi_dshow: Wrong audio structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
+		return E_FAIL;
+	    } else {
+		mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnsupportedMediaType,"get_available_formats_stream");
+		return E_FAIL;
+	    }
+	}
+    }
+    done = 0;
+
+    arpmt = (AM_MEDIA_TYPE **) malloc((count + 1) * sizeof(AM_MEDIA_TYPE *));
+    if (arpmt) {
+	memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *));
+
+	pBuf = (void **) malloc((count + 1) * sizeof(void *));
+	if (pBuf) {
+	    memset(pBuf, 0, (count + 1) * sizeof(void *));
+
+	    for (i = 0; i < count; i++) {
+		pBuf[i] = malloc(size);
+
+		if (!pBuf[i])
+		    break;
+
+		hr = OLE_CALL_ARGS(pStreamConfig, GetStreamCaps, i,
+			       &(arpmt[i]), pBuf[i]);
+		if (FAILED(hr))
+		    break;
+	    }
+	    if (i == count) {
+		*parpmtMedia = arpmt;
+		*parCaps = pBuf;
+		done = 1;
+	    }
+	}
+    }
+    if (!done) {
+	for (i = 0; i < count; i++) {
+	    if (pBuf && pBuf[i])
+		free(pBuf[i]);
+	    if (arpmt && arpmt[i])
+		DeleteMediaType(arpmt[i]);
+	}
+	if (pBuf)
+	    free(pBuf);
+	if (arpmt)
+	    free(arpmt);
+	if (hr != S_OK) {
+	    mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Call to GetStreamCaps failed (get_available_formats_stream)\n");
+	    return hr;
+	} else
+	    return E_OUTOFMEMORY;
+    }
+    return S_OK;
+}
+
+/**
+ * \brief returns allocates an array and store available media formats for given pin type to it 
+ * 
+ * \param pBuilder ICaptureGraphBuilder2 interface of graph builder
+ * \param pFilter IBaseFilter interface of capture device
+ * \param pMediaType media type for search (MEDIATYPE_Video or MEDIATYPE_Audio)
+ * \param[out] parpmtMediaType address of variable that receives pointer to array
+ *
+ * \return S_OK success
+ * \return E_POINTER one of given pointers is null
+ * \return apropriate error code otherwise
+ */
+static HRESULT get_available_formats_pin(ICaptureGraphBuilder2 * pBuilder,
+					 IBaseFilter * pFilter,
+					 const GUID * pMediaType,
+					 AM_MEDIA_TYPE *** parpmtMedia,
+					 void ***parCaps)
+{
+    IEnumMediaTypes *pEnum;
+    IPin *pPin;
+    int i, count, size;
+    ULONG cFetched;
+    AM_MEDIA_TYPE *pmt;
+    HRESULT hr;
+    void **pBuf;
+    AM_MEDIA_TYPE **arpmt;	//This will be real array
+    int isvideo;
+    VIDEO_STREAM_CONFIG_CAPS *pVideoCaps;
+    AUDIO_STREAM_CONFIG_CAPS *pAudioCaps;
+    int p1, p2, p3;
+
+    mp_msg(MSGT_TV, MSGL_DBG4,
+	   "tvi_dshow: get_available_formats_pin called\n");
+    if (!pBuilder || !pFilter || !pMediaType || !parpmtMedia)
+	return E_POINTER;
+
+    hr = OLE_CALL_ARGS(pBuilder, FindPin, (IUnknown *) pFilter,
+		   PINDIR_OUTPUT, NULL, pMediaType, FALSE, 0, &pPin);
+    if (FAILED(hr)) {
+	mp_msg(MSGT_TV, MSGL_DBG4,
+	       "tvi_dshow: Call to FindPin failed (get_available_formats_pin)\n");
+	return hr;
+    }
+    if (memcmp(pMediaType, &MEDIATYPE_Video, 16) == 0) {
+	isvideo = 1;
+	size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
+    } else if (memcmp(pMediaType, &MEDIATYPE_Audio, 16) == 0) {
+	isvideo = 0;
+	size = sizeof(AUDIO_STREAM_CONFIG_CAPS);
+    } else {
+	mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnsupportedMediaType,"get_available_formats_pin");
+	return E_FAIL;
+    }
+
+    hr = OLE_CALL_ARGS(pPin, EnumMediaTypes, &pEnum);
+    OLE_RELEASE_SAFE(pPin);
+    if (FAILED(hr)) {
+	mp_msg(MSGT_TV, MSGL_DBG4,
+	       "tvi_dshow: Call to EnumMediaTypes failed (get_available_formats_pin)\n");
+	return hr;
+    }
+    for (i = 0; OLE_CALL_ARGS(pEnum, Next, 1, &pmt, &cFetched) == S_OK; i++) {
+	if (!pmt)
+	    break;
+    }
+    OLE_CALL(pEnum,Reset);
+
+    count = i;
+    arpmt =
+	(AM_MEDIA_TYPE **) malloc((count + 1) * sizeof(AM_MEDIA_TYPE *));
+    if (!arpmt)
+	return E_OUTOFMEMORY;
+    memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *));
+
+    for (i = 0;
+	 i < count
+	 && OLE_CALL_ARGS(pEnum, Next, 1, &(arpmt[i]), &cFetched) == S_OK;
+	 i++);
+
+    OLE_RELEASE_SAFE(pEnum);
+
+
+    pBuf = (void **) malloc((count + 1) * sizeof(void *));
+    if (!pBuf) {
+	for (i = 0; i < count; i++)
+	    if (arpmt[i])
+		DeleteMediaType(arpmt[i]);
+	free(arpmt);
+	return E_OUTOFMEMORY;
+    }
+    memset(pBuf, 0, (count + 1) * sizeof(void *));
+
+    for (i = 0; i < count; i++) {
+	pBuf[i] = malloc(size);
+	if (!pBuf[i])
+	    break;
+	memset(pBuf[i], 0, size);
+
+	if (isvideo) {
+	    pVideoCaps = (VIDEO_STREAM_CONFIG_CAPS *) pBuf[i];
+	    extract_video_format(arpmt[i], NULL, &p1, &p2);
+	    pVideoCaps->MaxOutputSize.cx = pVideoCaps->MinOutputSize.cx =
+		p1;
+	    pVideoCaps->MaxOutputSize.cy = pVideoCaps->MinOutputSize.cy =
+		p2;
+	} else {
+	    pAudioCaps = (AUDIO_STREAM_CONFIG_CAPS *) pBuf[i];
+	    extract_audio_format(arpmt[i], &p1, &p2, &p3);
+	    pAudioCaps->MaximumSampleFrequency =
+		pAudioCaps->MinimumSampleFrequency = p1;
+	    pAudioCaps->MaximumBitsPerSample =
+		pAudioCaps->MinimumBitsPerSample = p2;
+	    pAudioCaps->MaximumChannels = pAudioCaps->MinimumChannels = p3;
+	}
+
+    }
+    if (i != count) {
+	for (i = 0; i < count; i++) {
+	    if (arpmt[i])
+		DeleteMediaType(arpmt[i]);
+	    if (pBuf[i])
+		free(pBuf[i]);
+	}
+	free(arpmt);
+	free(pBuf);
+	return E_OUTOFMEMORY;
+    }
+    *parpmtMedia = arpmt;
+    *parCaps = pBuf;
+
+    return S_OK;
+}
+
+/*
+*---------------------------------------------------------------------------------------
+*
+*  Public methods
+*
+*---------------------------------------------------------------------------------------
+*/
+/**
+ * \brief fills given buffer with audio data (usually one block)
+ *
+ * \param priv driver's private data structure 
+ * \param buffer buffer to store data to
+ * \param len buffer's size in bytes (usually one block size)
+ *
+ * \return audio pts if audio present, 1 - otherwise
+ */
+static double grab_audio_frame(priv_t * priv, char *buffer, int len)
+{
+    int bytes = 0;
+    int i;
+    double pts;
+    grabber_ringbuffer_t *rb = priv->a_buf;
+    grabber_ringbuffer_t *vrb = priv->v_buf;
+
+    if (!rb || !rb->ringbuffer)
+	return 1;
+
+    if(vrb && vrb->tStart<0){
+        memset(buffer,0,len);
+        return 0;
+    }
+    if(vrb && rb->tStart<0)
+        rb->tStart=vrb->tStart;
+
+    if (len < rb->blocksize)
+	bytes = len;
+    else
+	bytes = rb->blocksize;
+
+    mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (audio) called. %d blocks in buffer, %d bytes requested\n",
+	   rb->count, len);
+    if(!rb->count){
+        mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n");
+        for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000);
+        if(!rb->count){
+            mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n");
+            return 0;
+        }
+        mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n");
+    }
+
+    EnterCriticalSection(rb->pMutex);
+      pts=rb->dpts[rb->head]-rb->tStart;
+      memcpy(buffer, rb->ringbuffer[rb->head], bytes);
+      rb->head = (rb->head + 1) % rb->buffersize;
+      rb->count--;
+    LeaveCriticalSection(rb->pMutex);
+    return pts;
+}
+
+/**
+ * \brief returns audio frame size
+ *
+ * \param priv driver's private data structure 
+ *
+ * \return audio block size if audio enabled and 1 - otherwise
+ */
+static int get_audio_framesize(priv_t * priv)
+{
+    if (!priv->a_buf)
+	return 1;		//no audio       
+    mp_msg(MSGT_TV,MSGL_DBG3,"get_audio_framesize: %d\n",priv->a_buf->blocksize);
+    return priv->a_buf->blocksize;
+}
+
+#ifdef HAVE_TV_TELETEXT
+static int vbi_get_props(priv_t* priv,tt_stream_props* ptsp)
+{
+    if(!priv || !ptsp)
+        return TVI_CONTROL_FALSE;
+
+//STUBS!!!
+    ptsp->interlaced=0;
+    ptsp->offset=256;
+
+    ptsp->sampling_rate=27e6;
+    ptsp->samples_per_line=720;
+
+    ptsp->count[0]=16;
+    ptsp->count[1]=16;
+//END STUBS!!!
+    ptsp->bufsize = ptsp->samples_per_line * (ptsp->count[0] + ptsp->count[1]);
+
+    mp_msg(MSGT_TV,MSGL_V,"vbi_get_props: sampling_rate=%d,offset:%d,samples_per_line: %d\n interlaced:%s, count=[%d,%d]\n",    
+        ptsp->sampling_rate,
+        ptsp->offset,
+        ptsp->samples_per_line,
+        ptsp->interlaced?"Yes":"No",
+        ptsp->count[0],
+        ptsp->count[1]);
+
+    return TVI_CONTROL_TRUE;
+}
+
+static void vbi_grabber(priv_t* priv)
+{
+    grabber_ringbuffer_t *rb = priv->vbi_buf;
+    int i;
+    unsigned char* buf;
+    if (!rb || !rb->ringbuffer)
+	return;
+
+    buf=calloc(1,rb->blocksize);
+    for(i=0; i<23 && rb->count; i++){
+        memcpy(buf,rb->ringbuffer[rb->head],rb->blocksize);
+        teletext_control(priv->priv_vbi,TV_VBI_CONTROL_DECODE_PAGE,&buf);
+        rb->head = (rb->head + 1) % rb->buffersize;
+        rb->count--;
+    }
+    free(buf);
+}
+#endif //HAVE_TV_TELETEXT
+
+/**
+ * \brief fills given buffer with video data (usually one frame)
+ *
+ * \param priv driver's private data structure 
+ * \param buffer buffer to store data to
+ * \param len buffer's size in bytes (usually one frame size)
+ *
+ * \return frame size if video present, 0 - otherwise
+ */
+static double grab_video_frame(priv_t * priv, char *buffer, int len)
+{
+    int bytes = 0;
+    int i;
+    double pts;
+    grabber_ringbuffer_t *rb = priv->v_buf;
+
+    if (!rb || !rb->ringbuffer)
+	return 1;
+    if (len < rb->blocksize)
+	bytes = len;
+    else
+	bytes = rb->blocksize;
+
+    mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (video) called. %d blocks in buffer, %d bytes requested\n",
+	   rb->count, len);
+    if(!rb->count){
+        mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n");
+        for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000);
+        if(!rb->count){
+            mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n");
+            return 0;
+        }
+        mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n");
+    }
+    EnterCriticalSection(rb->pMutex);
+      if(rb->tStart<0)
+          rb->tStart=rb->dpts[rb->head];
+      pts=rb->dpts[rb->head]-rb->tStart;
+      memcpy(buffer, rb->ringbuffer[rb->head], bytes);
+      rb->head = (rb->head + 1) % rb->buffersize;
+      rb->count--;
+    LeaveCriticalSection(rb->pMutex);
+
+#ifdef HAVE_TV_TELETEXT
+    vbi_grabber(priv);
+#endif
+    return pts;
+}
+
+/**
+ * \brief returns frame size
+ *
+ * \param priv driver's private data structure 
+ *
+ * \return frame size if video present, 0 - otherwise
+ */
+static int get_video_framesize(priv_t * priv)
+{
+//      if(!priv->pmtVideo) return 1; //no video       
+//      return(priv->pmtVideo->lSampleSize);
+    if (!priv->v_buf)
+	return 1;		//no video       
+mp_msg(MSGT_TV,MSGL_DBG3,"geT_video_framesize: %d\n",priv->v_buf->blocksize);
+    return priv->v_buf->blocksize;
+}
+
+/**
+ * \brief calculate audio buffer size
+ * \param video_buf_size size of video buffer in bytes
+ * \param video_bitrate video bit rate
+ * \param audio_bitrate audio bit rate
+ * \return audio buffer isze in bytes
+ *
+ * \remarks length of video buffer and resulted audio buffer calculated in
+ * seconds will be the same.
+ */
+static inline int audio_buf_size_from_video(int video_buf_size, int video_bitrate, int audio_bitrate)
+{
+    int audio_buf_size = audio_bitrate * (video_buf_size / video_bitrate);
+    mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Audio capture buffer: %d * %d / %d = %d\n",
+            audio_bitrate,video_buf_size,video_bitrate,audio_buf_size);
+    return audio_buf_size;
+}
+
+/**
+ * \brief playback/capture real start
+ *
+ * \param priv driver's private data structure 
+ *
+ * \return 1 if success, 0 - otherwise
+ *
+ * TODO: move some code from init() here
+ */                          
+static int start(priv_t * priv)
+{
+    HRESULT hr;
+
+    if (priv->pVideoStreamConfig) {
+	hr = OLE_CALL_ARGS(priv->pVideoStreamConfig, SetFormat, priv->pmtVideo);
+	if (FAILED(hr)) {
+	    mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableSelectVideoFormat, (unsigned int)hr);
+	}
+    }
+
+    if (!priv->immediate_mode && priv->pAudioStreamConfig) {
+	hr = OLE_CALL_ARGS(priv->pAudioStreamConfig, SetFormat,
+		       priv->pmtAudio);
+	if (FAILED(hr)) {
+	    mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableSelectAudioFormat, (unsigned int)hr);
+	}
+    }
+
+    priv->v_buf=calloc(1,sizeof(grabber_ringbuffer_t));
+
+    if (priv->tv_param->buffer_size >= 0) {
+	priv->v_buf->buffersize = priv->tv_param->buffer_size;
+    } else {
+	priv->v_buf->buffersize = 16;
+    }
+
+    priv->v_buf->buffersize *= 1024 * 1024;
+    hr=build_sub_graph(priv, priv->pVideoFilter, priv->v_buf, priv->pmtVideo,&PIN_CATEGORY_CAPTURE);
+    if(FAILED(hr)){
+        mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildVideoSubGraph,(unsigned int)hr);
+        return 0;
+    }
+    if(priv->pmtAudio && !priv->immediate_mode){
+        priv->a_buf=calloc(1,sizeof(grabber_ringbuffer_t));
+
+        /* let the audio buffer be the same size (in seconds) than video one */
+        priv->a_buf->buffersize=audio_buf_size_from_video(
+                priv->v_buf->buffersize,
+                (((VIDEOINFOHEADER *) priv->pmtVideo->pbFormat)->dwBitRate),
+                (((WAVEFORMATEX *) (priv->pmtAudio->pbFormat))->nAvgBytesPerSec));
+
+        hr=build_sub_graph(priv, priv->pAudioFilter, priv->a_buf,priv->pmtAudio,&PIN_CATEGORY_CAPTURE);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildAudioSubGraph,(unsigned int)hr);
+            return 0;
+        }
+    }
+
+#ifdef HAVE_TV_TELETEXT
+    if(priv->tv_param->tdevice)
+    {
+        priv->vbi_buf=calloc(1,sizeof(grabber_ringbuffer_t));
+        init_ringbuffer(priv->vbi_buf,24,priv->tsp.bufsize);
+
+        priv->pmtVBI=calloc(1,sizeof(AM_MEDIA_TYPE));
+        priv->pmtVBI->majortype=MEDIATYPE_VBI;
+        hr=build_sub_graph(priv, priv->pVideoFilter, priv->vbi_buf,priv->pmtVBI,&PIN_CATEGORY_VBI);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildVBISubGraph,(unsigned int)hr);
+            return 0;
+        }
+    }
+#endif
+    /*
+       Graph is ready to capture. Starting graph.
+     */
+    if (mp_msg_test(MSGT_TV, MSGL_DBG2)) {
+	mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause 10sec\n");
+	usec_sleep(10000000);
+	mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause end\n");
+    }
+    if (!priv->pMediaControl) {
+        mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableGetMediaControlInterface,(unsigned int)E_POINTER);
+        return 0;
+    }
+    hr = OLE_CALL(priv->pMediaControl, Run);
+    if (FAILED(hr)) {
+	mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableStartGraph, (unsigned int)hr);
+	return 0;
+    }
+    mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Graph is started.\n");
+    priv->state = 1;
+
+    return (1);
+}
+
+/**
+ * \brief driver initialization
+ *
+ * \param priv driver's private data structure 
+ *
+ * \return 1 if success, 0 - otherwise
+ */
+static int init(priv_t * priv)
+{
+    HRESULT hr;
+    int result = 0;
+    long lInput, lTunerInput;
+    IEnumFilters *pEnum;
+    IBaseFilter *pFilter;
+    IPin *pVPOutPin;
+
+    priv->state=0;
+    CoInitialize(NULL);
+    do{
+        hr = CoCreateInstance((GUID *) & CLSID_FilterGraph, NULL,
+    			  CLSCTX_INPROC_SERVER, &IID_IGraphBuilder,
+    			  (void **) &priv->pGraph);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(FilterGraph) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+        //Debug
+        if (mp_msg_test(MSGT_TV, MSGL_DBG2)) {
+            AddToRot((IUnknown *) priv->pGraph, &(priv->dwRegister));
+        }
+
+        hr = CoCreateInstance((GUID *) & CLSID_CaptureGraphBuilder2, NULL,
+    			  CLSCTX_INPROC_SERVER, &IID_ICaptureGraphBuilder2,
+    			  (void **) &priv->pBuilder);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(CaptureGraphBuilder) call failed. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+    
+        hr = OLE_CALL_ARGS(priv->pBuilder, SetFiltergraph, priv->pGraph);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_ERR, "tvi_dshow: SetFiltergraph call failed. Error:0x%x\n",(unsigned int)hr);
+            break;
+        }
+    
+        mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available video capture devices\n");
+        priv->pVideoFilter = find_capture_device(priv->dev_index, &CLSID_VideoInputDeviceCategory);
+        if(!priv->pVideoFilter){
+            mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_NoVideoCaptureDevice);
+            break;
+        }
+        hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->pVideoFilter, NULL);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to add video capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr);
+            break;
+        }
+        mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available audio capture devices\n");
+        if (priv->adev_index != -1) {
+        	priv->pAudioFilter = find_capture_device(priv->adev_index, &CLSID_AudioInputDeviceCategory);	//output available audio edevices
+                if(!priv->pAudioFilter){
+                    mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_NoAudioCaptureDevice);
+                    break;
+                }
+
+        	hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->pAudioFilter, NULL);
+                if(FAILED(hr)){
+        	    mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Unable to add audio capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr);
+                    break;
+                }
+        } else
+        	hr = OLE_QUERYINTERFACE(priv->pVideoFilter, IID_IBaseFilter, priv->pAudioFilter);
+
+        hr = OLE_QUERYINTERFACE(priv->pVideoFilter, IID_IAMVideoProcAmp,priv->pVideoProcAmp);
+        if (FAILED(hr) && hr != E_NOINTERFACE)
+            mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get IID_IAMVideoProcAmp failed (0x%x).\n", (unsigned int)hr);
+
+        if (hr != S_OK) {
+            mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_VideoAdjustigNotSupported);
+            priv->pVideoProcAmp = NULL;
+        }
+
+        hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
+        		   &PIN_CATEGORY_CAPTURE,
+        		   &MEDIATYPE_Video,
+        		   priv->pVideoFilter,
+        		   &IID_IAMCrossbar, (void **) &(priv->pCrossbar));
+        if (FAILED(hr)) {
+            mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_SelectingInputNotSupported);
+            priv->pCrossbar = NULL;
+        }
+
+        hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
+        		   &PIN_CATEGORY_CAPTURE,
+        		   &MEDIATYPE_Video,
+        		   priv->pVideoFilter,
+        		   &IID_IAMStreamConfig,
+        		   (void **) &(priv->pVideoStreamConfig));
+        if (FAILED(hr)) {
+            mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_ChangingWidthHeightNotSupported);
+            priv->pVideoStreamConfig = NULL;
+        }
+
+        hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
+		   &PIN_CATEGORY_CAPTURE,
+		   &MEDIATYPE_Audio,
+		   priv->pAudioFilter,
+		   &IID_IAMStreamConfig,
+		   (void **) &(priv->pAudioStreamConfig));
+        if (FAILED(hr)) {
+            mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get IAMStreamConfig(audio) failed (0x%x).\n", (unsigned int)hr);
+            priv->pAudioStreamConfig = NULL;
+        }
+
+        if (priv->tv_param->amode >= 0) {
+	    IAMTVAudio *pTVAudio;
+	    hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface, NULL, NULL,priv->pVideoFilter,&IID_IAMTVAudio, (void *) &pTVAudio);
+            if (hr == S_OK) {
+                switch (priv->tv_param->amode) {
+                case 0:
+                    hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_MONO);
+                    break;
+                case 1:
+                    hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_STEREO);
+                    break;
+                case 2:
+                    hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode,
+			       AMTVAUDIO_MODE_LANG_A);
+                    break;
+                case 3:
+                    hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode,
+			       AMTVAUDIO_MODE_LANG_B);
+                    break;
+                }
+                OLE_RELEASE_SAFE(pTVAudio);
+                if (FAILED(hr))
+                    mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_UnableSetAudioMode, priv->tv_param->amode,(unsigned int)hr);
+            }
+        }
+        /* 
+           Getting available video formats (last pointer in array  will be NULL) 
+           First tryin to call IAMStreamConfig::GetStreamCaos. this will give us additional information such as
+           min/max picture dimensions, etc. If this call fails trying IPIn::EnumMediaTypes with default
+           min/max values.
+         */
+
+        hr = get_available_formats_stream(priv->pVideoStreamConfig,
+				      &MEDIATYPE_Video,
+				      &(priv->arpmtVideo),
+				      (void ***) &(priv->arVideoCaps));
+        if (FAILED(hr)) {
+            mp_msg(MSGT_TV, MSGL_DBG2, "Unable to use IAMStreamConfig for retriving available video formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr);
+            hr = get_available_formats_pin(priv->pBuilder, priv->pVideoFilter,
+				       &MEDIATYPE_Video,
+				       &(priv->arpmtVideo),
+				       (void ***) &(priv->arVideoCaps));
+            if(FAILED(hr)){
+                mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableGetsupportedVideoFormats, (unsigned int)hr);
+                break;
+            }
+        }
+        priv->nVideoFormatUsed = 0;
+
+        if (!priv->arpmtVideo[priv->nVideoFormatUsed]
+            || !extract_video_format(priv->arpmtVideo[priv->nVideoFormatUsed],
+				 &(priv->fcc), &(priv->width),
+				 &(priv->height))) {
+            mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_ErrorParsingVideoFormatStruct);
+            break;
+        }
+        priv->pmtVideo = CreateMediaType(priv->arpmtVideo[priv->nVideoFormatUsed]);
+        /* 
+           Getting available audio formats (last pointer in array will be NULL)
+         */
+        hr = get_available_formats_stream(priv->pAudioStreamConfig,
+				      &MEDIATYPE_Audio,
+				      &(priv->arpmtAudio),
+				      (void ***) &(priv->arAudioCaps));
+        if (FAILED(hr)) {
+            mp_msg(MSGT_TV, MSGL_DBG2, "Unable to use IAMStreamConfig for retriving available audio formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr);
+            hr = get_available_formats_pin(priv->pBuilder, priv->pAudioFilter,
+				       &MEDIATYPE_Audio,
+				       &(priv->arpmtAudio),
+				       (void ***) &(priv->arAudioCaps));
+            if (FAILED(hr)) {
+                mp_msg(MSGT_TV,MSGL_WARN, MSGTR_TVI_DS_UnableGetsupportedAudioFormats, (unsigned int)hr);
+                /* 
+                   Following combination will disable sound
+                 */
+                priv->arpmtAudio = (AM_MEDIA_TYPE **) malloc(sizeof(AM_MEDIA_TYPE *));
+                priv->arpmtAudio[0] = NULL;
+                priv->pmtAudio = NULL;
+                priv->pAudioStreamConfig = NULL;
+            }
+        }
+        /* debug */
+        {
+            int i;
+            for (i = 0; priv->arpmtVideo[i]; i++) {
+                DisplayMediaType("Available video format", priv->arpmtVideo[i]);
+            }
+            for (i = 0; priv->arpmtAudio[i]; i++) {
+                DisplayMediaType("Available audio format", priv->arpmtAudio[i]);
+            }
+        }
+        priv->nAudioFormatUsed = 0;
+        if (priv->arpmtAudio[priv->nAudioFormatUsed]) {
+            priv->pmtAudio = CreateMediaType(priv->arpmtAudio[priv->nAudioFormatUsed]);
+            if (!extract_audio_format(priv->pmtAudio, &(priv->samplerate), NULL, NULL)) {
+                mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_ErrorParsingAudioFormatStruct);
+                DisplayMediaType("audio format failed",priv->arpmtAudio[priv->nAudioFormatUsed]);
+                break;
+            }
+        }
+        show_filter_info(priv->pVideoFilter);
+
+        hr = OLE_QUERYINTERFACE(priv->pGraph, IID_IMediaControl,priv->pMediaControl);
+        if(FAILED(hr)){
+            mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableGetMediaControlInterface,(unsigned int)hr);
+            break;
+        }
+        hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
+		   &PIN_CATEGORY_CAPTURE, NULL,
+		   priv->pVideoFilter,
+		   &IID_IAMTVTuner, (void **) &(priv->pTVTuner));
+
+        if (!priv->pTVTuner) {
+            mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to access IAMTVTuner (0x%x)\n", (unsigned int)hr);
+        }
+
+        // shows Tuner capabilities
+        get_capabilities(priv);
+
+        if (priv->pTVTuner) {
+            hr = OLE_CALL_ARGS(priv->pTVTuner, put_CountryCode,
+		       chanlist2country(priv->tv_param->chanlist));
+            if(FAILED(hr)){
+                mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_CountryCode failed. Error:0x%x\n",(unsigned int)hr);
+                break;
+            }
+
+            hr = OLE_CALL_ARGS(priv->pTVTuner, put_Mode, AMTUNER_MODE_TV);
+            if(FAILED(hr)){
+                mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_Mode failed. Error:0x%x\n",(unsigned int)hr);
+                break;
+            }
+
+            hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput);
+            if(FAILED(hr)){
+                mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to get_ConnectInput failed. Error:0x%x\n",(unsigned int)hr);
+                break;
+            }
+
+            /* small hack */
+            lTunerInput = strstr(priv->tv_param->chanlist, "cable") ? TunerInputCable : TunerInputAntenna;
+
+            hr = OLE_CALL_ARGS(priv->pTVTuner, put_InputType, lInput, lTunerInput);
+            if(FAILED(hr)){
+                mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_InputType failed. Error:0x%x\n",(unsigned int)hr);
+                break;
+            }
+
+        }
+
+        /**
+         for VIVO  cards we should check if preview pin is available on video capture device.
+         If it is not, we have to connect Video Port Manager filter to VP pin of capture device filter.
+         Otherwise we will get 0x8007001f (Device is not functioning properly) when attempting to start graph
+        */
+        hr = OLE_CALL_ARGS(priv->pBuilder, FindPin,
+		   (IUnknown *) priv->pVideoFilter,
+		   PINDIR_OUTPUT,
+		   &PIN_CATEGORY_VIDEOPORT, NULL, FALSE,
+		   0, (IPin **) & pVPOutPin);
+        if (SUCCEEDED(hr)) {
+            hr = OLE_CALL_ARGS(priv->pGraph, Render, pVPOutPin);
+            OLE_RELEASE_SAFE(pVPOutPin);
+
+            if (FAILED(hr)) {
+                mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableTerminateVPPin, (unsigned int)hr);
+                break;
+            }
+        }
+
+        OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum);
+        while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) {
+            LPVIDEOWINDOW pVideoWindow;
+            hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow);
+            if (SUCCEEDED(hr))
+            {
+                if(priv->tv_param->hidden_vp_renderer){
+                    OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0);
+                    OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0);
+                }else
+                {
+                    OLE_CALL_ARGS(priv->pGraph, RemoveFilter, pFilter);
+                }
+                OLE_RELEASE_SAFE(pVideoWindow);
+            }
+            OLE_RELEASE_SAFE(pFilter);
+        }
+        OLE_RELEASE_SAFE(pEnum);
+        if(priv->tv_param->system_clock)
+        {
+            LPREFERENCECLOCK rc;
+            IBaseFilter* pBF;
+            hr = CoCreateInstance((GUID *) & CLSID_SystemClock, NULL,
+			      CLSCTX_INPROC_SERVER, &IID_IReferenceClock,
+			      (void *) &rc);
+
+            OLE_QUERYINTERFACE(priv->pBuilder,IID_IBaseFilter,pBF);
+            OLE_CALL_ARGS(pBF,SetSyncSource,rc);
+        }
+#ifdef HAVE_TV_TELETEXT
+       if(vbi_get_props(priv,&(priv->tsp))!=TVI_CONTROL_TRUE)
+           break;
+#endif
+        result = 1;
+    } while(0);
+
+    if (!result){
+        mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_GraphInitFailure);
+	uninit(priv);
+    }
+    return result;
+}
+
+/**
+ * \brief driver uninitialization
+ *
+ * \param priv driver's private data structure 
+ *
+ * \return always 1
+ */
+static int uninit(priv_t * priv)
+{
+    int i;
+    if (!priv)
+	return (1);
+    //Debug
+    if (priv->dwRegister) {
+        RemoveFromRot(priv->dwRegister);
+    }
+#ifdef HAVE_TV_TELETEXT
+    teletext_control(priv->priv_vbi,TV_VBI_CONTROL_STOP,(void*)1);
+#endif
+    //stop audio grabber thread
+
+    if (priv->state && priv->pMediaControl) {
+	OLE_CALL(priv->pMediaControl, Stop);
+    }
+    OLE_RELEASE_SAFE(priv->pMediaControl);
+    priv->state = 0;
+
+    if (priv->pGraph) {
+	if (priv->pVideoFilter)
+	    OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->pVideoFilter);
+	if (priv->pAudioFilter)
+	    OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->pAudioFilter);
+    }
+    OLE_RELEASE_SAFE(priv->pCrossbar);
+    OLE_RELEASE_SAFE(priv->pVideoStreamConfig);
+    OLE_RELEASE_SAFE(priv->pAudioStreamConfig);
+    OLE_RELEASE_SAFE(priv->pVideoProcAmp);
+    OLE_RELEASE_SAFE(priv->pVideoFilter);
+    OLE_RELEASE_SAFE(priv->pAudioFilter);
+    OLE_RELEASE_SAFE(priv->pGraph);
+    OLE_RELEASE_SAFE(priv->pBuilder);
+    OLE_RELEASE_SAFE(priv->pCSGCB);
+
+    if (priv->pmtVideo)
+	DeleteMediaType(priv->pmtVideo);
+    if (priv->pmtAudio)
+	DeleteMediaType(priv->pmtAudio);
+    if (priv->pmtVBI)
+	DeleteMediaType(priv->pmtVBI);
+
+    if (priv->arpmtVideo) {
+	for (i = 0; priv->arpmtVideo[i]; i++) {
+	    DeleteMediaType(priv->arpmtVideo[i]);
+	}
+	free(priv->arpmtVideo);
+    }
+    if (priv->arVideoCaps) {
+	for (i = 0; priv->arVideoCaps[i]; i++) {
+	    free(priv->arVideoCaps[i]);
+	}
+	free(priv->arVideoCaps);
+    }
+    if (priv->arpmtAudio) {
+	for (i = 0; priv->arpmtAudio[i]; i++) {
+	    DeleteMediaType(priv->arpmtAudio[i]);
+	}
+	free(priv->arpmtAudio);
+    }
+    if (priv->arAudioCaps) {
+	for (i = 0; priv->arAudioCaps[i]; i++) {
+	    free(priv->arAudioCaps[i]);
+	}
+	free(priv->arAudioCaps);
+    }
+    if (priv->a_buf) {
+	destroy_ringbuffer(priv->a_buf);
+	free(priv->a_buf);
+	priv->a_buf = NULL;
+    }
+    if (priv->v_buf) {
+	destroy_ringbuffer(priv->v_buf);
+	free(priv->v_buf);
+	priv->v_buf = NULL;
+    }
+    if (priv->vbi_buf) {
+	destroy_ringbuffer(priv->vbi_buf);
+	free(priv->vbi_buf);
+	priv->vbi_buf = NULL;
+    }
+    if(priv->freq_table){
+        priv->freq_table_len=-1;
+        free(priv->freq_table);
+        priv->freq_table=NULL;
+    }
+    CoUninitialize();
+    return (1);
+}
+
+/**
+ * \brief driver pre-initialization
+ *
+ * \param device string, containing device name in form "x[.y]", where x is video capture device
+ *               (default: 0, first available); y (if given)  sets audio capture device
+ *
+ * \return 1 if success,0 - otherwise
+ */
+static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param)
+{
+    tvi_handle_t *h;
+    priv_t *priv;
+    int a;
+
+    h = new_handle();
+    if (!h)
+	return (NULL);
+
+    priv = h->priv;
+
+    memset(priv, 0, sizeof(priv_t));
+    priv->direct_setfreq_call = 1;	//first using direct call. if it fails, workaround will be enabled
+    priv->direct_getfreq_call = 1;	//first using direct call. if it fails, workaround will be enabled
+    priv->adev_index = -1;
+    priv->freq_table_len=-1;
+    priv->tv_param=tv_param;
+
+    if (tv_param->device) {
+	if (sscanf(tv_param->device, "%d", &a) == 1) {
+	    priv->dev_index = a;
+	} else {
+	    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongDeviceParam, tv_param->device);
+	    free_handle(h);
+	    return NULL;
+	}
+	if (priv->dev_index < 0) {
+	    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongDeviceIndex, a);
+	    free_handle(h);
+	    return NULL;
+	}
+    }
+    if (tv_param->adevice) {
+	if (sscanf(tv_param->adevice, "%d", &a) == 1) {
+	    priv->adev_index = a;
+	} else {
+	    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongADeviceParam, tv_param->adevice);
+	    free_handle(h);
+	    return NULL;
+	}
+	if (priv->dev_index < 0) {
+	    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongADeviceIndex, a);
+	    free_handle(h);
+	    return NULL;
+	}
+    }
+    return h;
+}
+
+/**
+ * \brief driver's ioctl handler
+ *
+ * \param priv driver's private data structure 
+ * \param cmd ioctl command
+ * \param arg ioct command's parameter
+ *
+ * \return TVI_CONTROL_TRUE if success 
+ * \return TVI_CONTROL_FALSE if failure
+ * \return TVI_CONTROL_UNKNOWN if unknowm cmd called
+ */
+static int control(priv_t * priv, int cmd, void *arg)
+{
+    switch (cmd) {
+/* need rewrite */
+    case TVI_CONTROL_VID_SET_FORMAT:
+	{
+	    int fcc, i;
+	    if (priv->state)
+		return TVI_CONTROL_FALSE;
+	    fcc = *(int *) arg;
+
+            if(!priv->arpmtVideo)
+                return TVI_CONTROL_FALSE;
+	    for (i = 0; priv->arpmtVideo[i]; i++)
+		if (check_video_format
+		    (priv->arpmtVideo[i], fcc, priv->width, priv->height))
+		    break;
+	    if (!priv->arpmtVideo[i])
+		return TVI_CONTROL_FALSE;
+
+	    priv->nVideoFormatUsed = i;
+
+	    if (priv->pmtVideo)
+		DeleteMediaType(priv->pmtVideo);
+	    priv->pmtVideo =
+		CreateMediaType(priv->arpmtVideo[priv->nVideoFormatUsed]);
+	    DisplayMediaType("VID_SET_FORMAT", priv->pmtVideo);
+	    /*
+	       Setting width & height to preferred by driver values
+	     */
+	    extract_video_format(priv->arpmtVideo[priv->nVideoFormatUsed],
+				 &(priv->fcc), &(priv->width),
+				 &(priv->height));
+	    return TVI_CONTROL_TRUE;
+	}
+    case TVI_CONTROL_VID_GET_FORMAT:
+	{
+            if(!priv->pmtVideo)
+                return TVI_CONTROL_FALSE;
+	    DisplayMediaType("VID_GET_FORMAT", priv->pmtVideo);
+	    if (priv->fcc) {
+		*(int *) arg = priv->fcc;
+		return (TVI_CONTROL_TRUE);
+	    } else
+		return (TVI_CONTROL_FALSE);
+	}
+    case TVI_CONTROL_VID_SET_WIDTH:
+	{
+	    VIDEO_STREAM_CONFIG_CAPS *pCaps;
+	    VIDEOINFOHEADER *Vhdr;
+	    int width = *(int *) arg;
+	    if (priv->state)
+		return TVI_CONTROL_FALSE;
+
+	    pCaps = priv->arVideoCaps[priv->nVideoFormatUsed];
+	    if (!pCaps)
+		return TVI_CONTROL_FALSE;
+	    if (width < pCaps->MinOutputSize.cx
+		|| width > pCaps->MaxOutputSize.cx)
+		return TVI_CONTROL_FALSE;
+
+	    if (width % pCaps->OutputGranularityX)
+		return TVI_CONTROL_FALSE;
+
+	    if (!priv->pmtVideo || !priv->pmtVideo->pbFormat)
+		return TVI_CONTROL_FALSE;
+	    Vhdr = (VIDEOINFOHEADER *) priv->pmtVideo->pbFormat;
+	    Vhdr->bmiHeader.biWidth = width;
+	    priv->pmtVideo->lSampleSize = Vhdr->bmiHeader.biSizeImage =
+		labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth *
+		     Vhdr->bmiHeader.biHeight) >> 3;
+
+	    priv->width = width;
+
+	    return (TVI_CONTROL_TRUE);
+	}
+    case TVI_CONTROL_VID_GET_WIDTH:
+	{
+	    if (priv->width) {
+		*(int *) arg = priv->width;
+		return (TVI_CONTROL_TRUE);
+	    } else
+		return TVI_CONTROL_FALSE;
+	}
+    case TVI_CONTROL_VID_CHK_WIDTH:
+	{
+	    VIDEO_STREAM_CONFIG_CAPS *pCaps;
+	    int width = *(int *) arg;
+	    pCaps = priv->arVideoCaps[priv->nVideoFormatUsed];
+	    if (!pCaps)
+		return TVI_CONTROL_FALSE;
+	    if (width < pCaps->MinOutputSize.cx
+		|| width > pCaps->MaxOutputSize.cx)
+		return TVI_CONTROL_FALSE;
+
+	    if (width % pCaps->OutputGranularityX)
+		return TVI_CONTROL_FALSE;
+	    return (TVI_CONTROL_TRUE);
+	}
+    case TVI_CONTROL_VID_SET_HEIGHT:
+	{
+	    VIDEO_STREAM_CONFIG_CAPS *pCaps;
+	    VIDEOINFOHEADER *Vhdr;
+	    int height = *(int *) arg;
+	    if (priv->state)
+		return TVI_CONTROL_FALSE;
+
+	    pCaps = priv->arVideoCaps[priv->nVideoFormatUsed];
+	    if (!pCaps)
+		return TVI_CONTROL_FALSE;
+	    if (height < pCaps->MinOutputSize.cy
+		|| height > pCaps->MaxOutputSize.cy)
+		return TVI_CONTROL_FALSE;
+
+	    if (height % pCaps->OutputGranularityY)
+		return TVI_CONTROL_FALSE;
+
+	    if (!priv->pmtVideo || !priv->pmtVideo->pbFormat)
+		return TVI_CONTROL_FALSE;
+	    Vhdr = (VIDEOINFOHEADER *) priv->pmtVideo->pbFormat;
+
+	    if (Vhdr->bmiHeader.biHeight < 0)
+		Vhdr->bmiHeader.biHeight = -height;
+	    else
+		Vhdr->bmiHeader.biHeight = height;
+	    priv->pmtVideo->lSampleSize = Vhdr->bmiHeader.biSizeImage =
+		labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth *
+		     Vhdr->bmiHeader.biHeight) >> 3;
+
+	    priv->height = height;
+	    return (TVI_CONTROL_TRUE);
+	}
+    case TVI_CONTROL_VID_GET_HEIGHT:
+	{
+	    if (priv->height) {
+		*(int *) arg = priv->height;
+		return (TVI_CONTROL_TRUE);
+	    } else
+		return TVI_CONTROL_FALSE;
+	}
+    case TVI_CONTROL_VID_CHK_HEIGHT:
+	{
+	    VIDEO_STREAM_CONFIG_CAPS *pCaps;
+	    int height = *(int *) arg;
+	    pCaps = priv->arVideoCaps[priv->nVideoFormatUsed];
+	    if (!pCaps)
+		return TVI_CONTROL_FALSE;
+	    if (height < pCaps->MinOutputSize.cy
+		|| height > pCaps->MaxOutputSize.cy)
+		return TVI_CONTROL_FALSE;
+
+	    if (height % pCaps->OutputGranularityY)
+		return TVI_CONTROL_FALSE;
+
+	    return (TVI_CONTROL_TRUE);
+	}
+    case TVI_CONTROL_IS_AUDIO:
+	if (!priv->pmtAudio)
+	    return TVI_CONTROL_FALSE;
+	else
+	    return TVI_CONTROL_TRUE;
+    case TVI_CONTROL_IS_VIDEO:
+	return TVI_CONTROL_TRUE;
+    case TVI_CONTROL_AUD_GET_FORMAT:
+	{
+	    *(int *) arg = AF_FORMAT_S16_LE;
+	    if (!priv->pmtAudio)
+		return TVI_CONTROL_FALSE;
+	    else
+		return TVI_CONTROL_TRUE;
+	}
+    case TVI_CONTROL_AUD_GET_CHANNELS:
+	{
+	    *(int *) arg = priv->channels;
+	    if (!priv->pmtAudio)
+		return TVI_CONTROL_FALSE;
+	    else
+		return TVI_CONTROL_TRUE;
+	}
+    case TVI_CONTROL_AUD_SET_SAMPLERATE:
+	{
+	    int i, samplerate;
+	    if (priv->state)
+		return TVI_CONTROL_FALSE;
+	    if (!priv->arpmtAudio[0])
+		return TVI_CONTROL_FALSE;
+
+	    samplerate = *(int *) arg;;
+
+	    for (i = 0; priv->arpmtAudio[i]; i++)
+		if (check_audio_format
+		    (priv->arpmtAudio[i], samplerate, 16, priv->channels))
+		    break;
+	    if (!priv->arpmtAudio[i]) {	
+                //request not found. failing back to first available
+		mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_SamplerateNotsupported, samplerate);
+		i = 0;
+	    }
+	    if (priv->pmtAudio)
+		DeleteMediaType(priv->pmtAudio);
+	    priv->pmtAudio = CreateMediaType(priv->arpmtAudio[i]);
+	    extract_audio_format(priv->arpmtAudio[i], &(priv->samplerate),
+				 NULL, &(priv->channels));
+	    return TVI_CONTROL_TRUE;
+	}
+    case TVI_CONTROL_AUD_GET_SAMPLERATE:
+	{
+	    *(int *) arg = priv->samplerate;
+	    if (!priv->samplerate)
+		return TVI_CONTROL_FALSE;
+	    if (!priv->pmtAudio)
+		return TVI_CONTROL_FALSE;
+	    else
+		return TVI_CONTROL_TRUE;
+	}
+    case TVI_CONTROL_AUD_GET_SAMPLESIZE:
+	{
+	    WAVEFORMATEX *pWF;
+	    if (!priv->pmtAudio)
+		return TVI_CONTROL_FALSE;
+	    if (!priv->pmtAudio->pbFormat)
+		return TVI_CONTROL_FALSE;
+	    pWF = (WAVEFORMATEX *) priv->pmtAudio->pbFormat;
+	    *(int *) arg = pWF->wBitsPerSample / 8;
+	    return TVI_CONTROL_TRUE;
+	}
+    case TVI_CONTROL_IS_TUNER:
+	{
+	    if (!priv->pTVTuner)
+		return TVI_CONTROL_FALSE;
+
+	    return (TVI_CONTROL_TRUE);
+	}
+    case TVI_CONTROL_TUN_SET_NORM:
+	{
+	    IAMAnalogVideoDecoder *pVD;
+	    long lAnalogFormat;
+	    int i;
+	    HRESULT hr;
+
+	    i = *(int *) arg;
+	    i--;
+	    if (i < 0 || i >= tv_available_norms_count)
+		return TVI_CONTROL_FALSE;
+	    lAnalogFormat = tv_norms[tv_available_norms[i]].index;
+
+	    hr = OLE_QUERYINTERFACE(priv->pVideoFilter,IID_IAMAnalogVideoDecoder, pVD);
+	    if (hr != S_OK)                            
+		return TVI_CONTROL_FALSE;
+	    hr = OLE_CALL_ARGS(pVD, get_TVFormat, &lAnalogFormat);
+	    OLE_RELEASE_SAFE(pVD);
+	    if (FAILED(hr))
+		return (TVI_CONTROL_FALSE);
+	    else
+		return (TVI_CONTROL_TRUE);
+	}
+    case TVI_CONTROL_TUN_GET_NORM:
+	{
+	    long lAnalogFormat;
+	    int i;
+	    HRESULT hr;
+	    IAMAnalogVideoDecoder *pVD;
+
+	    hr = OLE_QUERYINTERFACE(priv->pVideoFilter,IID_IAMAnalogVideoDecoder, pVD);
+	    if (hr == S_OK) {
+		hr = OLE_CALL_ARGS(pVD, get_TVFormat, &lAnalogFormat);
+		OLE_RELEASE_SAFE(pVD);
+	    }
+
+	    if (FAILED(hr)) {	//trying another method
+		if (!priv->pTVTuner)
+		    return TVI_CONTROL_FALSE;
+                hr=OLE_CALL_ARGS(priv->pTVTuner, get_TVFormat, &lAnalogFormat);
+		if (FAILED(hr))
+		    return TVI_CONTROL_FALSE;
+	    }
+	    for (i = 0; i < tv_available_norms_count; i++) {
+		if (tv_norms[tv_available_norms[i]].index == lAnalogFormat) {
+		    *(int *) arg = i + 1;
+		    return TVI_CONTROL_TRUE;
+		}
+	    }
+	    return (TVI_CONTROL_FALSE);
+	}
+    case TVI_CONTROL_SPC_GET_NORMID:
+	{
+	    int i;
+	    if (!priv->pTVTuner)
+		return TVI_CONTROL_FALSE;
+	    for (i = 0; i < tv_available_norms_count; i++) {
+		if (!strcasecmp
+		    (tv_norms[tv_available_norms[i]].name, (char *) arg)) {
+		    *(int *) arg = i + 1;
+		    return TVI_CONTROL_TRUE;
+		}
+	    }
+	    return TVI_CONTROL_FALSE;
+	}
+    case TVI_CONTROL_SPC_SET_INPUT:
+	{
+	    return set_crossbar_input(priv, *(int *) arg);
+	}
+    case TVI_CONTROL_TUN_GET_FREQ:
+	{
+	    unsigned long lFreq;
+	    int ret;
+	    if (!priv->pTVTuner)
+		return TVI_CONTROL_FALSE;
+
+	    ret = get_frequency(priv, &lFreq);
+	    lFreq = lFreq * 16 / 1000000;	//convert from Hz to 1/16 MHz units
+
+	    *(unsigned long *) arg = lFreq;
+	    return ret;
+	}
+    case TVI_CONTROL_TUN_SET_FREQ:
+	{
+	    unsigned long nFreq = *(unsigned long *) arg;
+	    if (!priv->pTVTuner)
+		return TVI_CONTROL_FALSE;
+	    //convert to Hz
+	    nFreq = 1000000 * nFreq / 16;	//convert from 1/16 MHz units to Hz
+	    return set_frequency(priv, nFreq);
+	}
+    case TVI_CONTROL_VID_SET_HUE:
+	return set_control(priv, VideoProcAmp_Hue, *(int *) arg);
+    case TVI_CONTROL_VID_GET_HUE:
+	return get_control(priv, VideoProcAmp_Hue, (int *) arg);
+    case TVI_CONTROL_VID_SET_CONTRAST:
+	return set_control(priv, VideoProcAmp_Contrast, *(int *) arg);
+    case TVI_CONTROL_VID_GET_CONTRAST:
+	return get_control(priv, VideoProcAmp_Contrast, (int *) arg);
+    case TVI_CONTROL_VID_SET_SATURATION:
+	return set_control(priv, VideoProcAmp_Saturation, *(int *) arg);
+    case TVI_CONTROL_VID_GET_SATURATION:
+	return get_control(priv, VideoProcAmp_Saturation, (int *) arg);
+    case TVI_CONTROL_VID_SET_BRIGHTNESS:
+	return set_control(priv, VideoProcAmp_Brightness, *(int *) arg);
+    case TVI_CONTROL_VID_GET_BRIGHTNESS:
+	return get_control(priv, VideoProcAmp_Brightness, (int *) arg);
+
+    case TVI_CONTROL_VID_GET_FPS:
+	{
+	    VIDEOINFOHEADER *Vhdr;
+	    if (!priv->pmtVideo)
+		return TVI_CONTROL_FALSE;
+	    if (!priv->pmtVideo->pbFormat)
+		return TVI_CONTROL_FALSE;
+	    Vhdr = (VIDEOINFOHEADER *) priv->pmtVideo->pbFormat;
+	    *(float *) arg =
+		(1.0 * Vhdr->dwBitRate) / Vhdr->bmiHeader.biSizeImage;
+	    return TVI_CONTROL_TRUE;
+	}
+    case TVI_CONTROL_IMMEDIATE:
+	priv->immediate_mode = 1;
+	return TVI_CONTROL_TRUE;
+#ifdef HAVE_TV_TELETEXT
+    case TVI_CONTROL_VBI_INIT:
+    {
+        void* ptr;
+        ptr=&(priv->tsp);
+        if(teletext_control(NULL,TV_VBI_CONTROL_START,&ptr)==TVI_CONTROL_TRUE)
+            priv->priv_vbi=ptr;
+        else
+            priv->priv_vbi=NULL;
+        return TVI_CONTROL_TRUE;
+    }
+    default:
+        return teletext_control(priv->priv_vbi,cmd,arg);
+#endif
+    }
+    return (TVI_CONTROL_UNKNOWN);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stream/tvi_dshow.h	Sat Oct 13 17:14:39 2007 +0000
@@ -0,0 +1,693 @@
+#ifndef TVI_DSHOW_H_
+#define TVI_DSHOW_H_
+
+/// \defgroup tvi_dshow TV driver (Directshow)
+
+#define INITGUID
+#include <inttypes.h>
+//#include <ole2.h>
+#include <vfw.h>
+#include "loader/dshow/mediatype.h"
+#include "loader/dshow/guids.h"
+
+#define wtoa(strW,strA,lenA) WideCharToMultiByte(0,0,strW,-1,strA,lenA,NULL,NULL)
+#define atow(strA,strW,lenW) MultiByteToWideChar(0,0,strA,strlen(strA),strW,lenW)
+
+typedef struct DISPPARAMS *LPDISPPARAMS;
+typedef struct IFileSinkFilter *LPFILESINKFILTER;
+typedef struct IAMCopyCaptureFileProgress *LPAMCOPYCAPTUREFILEPROGRESS;
+typedef struct IErrorLog *LPERRORLOG;
+typedef struct IAMTunerNotification *LPAMTUNERNOTIFICATION;
+typedef struct IFilterGraph *LPFILTERGRAPH;
+typedef struct IBaseFilter *LPBASEFILTER;
+typedef struct IPin *LPPIN;
+typedef struct IEnumPins *LPENUMPINS;
+typedef struct IEnumFilters *LPENUMFILTERS;
+typedef struct IEnumMediaTypes *LPENUMMEDIATYPES;
+typedef struct IReferenceClock *LPREFERENCECLOCK;
+typedef struct IMediaSample *LPMEDIASAMPLE;
+typedef struct IVideoWindow *LPVIDEOWINDOW;
+
+typedef struct 
+{
+    long cBuffers;
+    long cbBuffer;
+    long cbAlign;
+    long cbPrefix;
+}ALLOCATOR_PROPERTIES;
+
+typedef
+    enum tagTunerInputType { TunerInputCable = 0,
+    TunerInputAntenna = TunerInputCable + 1
+} TunerInputType;
+typedef enum tagAMTunerModeType {
+    AMTUNER_MODE_DEFAULT = 0x0000,
+    AMTUNER_MODE_TV = 0x0001,
+    AMTUNER_MODE_FM_RADIO = 0x0002,
+    AMTUNER_MODE_AM_RADIO = 0x0004,
+    AMTUNER_MODE_DSS = 0x0008
+} AMTunerModeType;
+enum tagAMTunerSubChannel { AMTUNER_SUBCHAN_NO_TUNE = -2,
+    AMTUNER_SUBCHAN_DEFAULT = -1
+} AMTunerSubChannel;
+typedef enum tagVideoProcAmpProperty {
+    VideoProcAmp_Brightness,
+    VideoProcAmp_Contrast,
+    VideoProcAmp_Hue,
+    VideoProcAmp_Saturation,
+    VideoProcAmp_Sharpness,
+    VideoProcAmp_Gamma,
+    VideoProcAmp_ColorEnable,
+    VideoProcAmp_WhiteBalance,
+    VideoProcAmp_BacklightCompensation,
+    VideoProcAmp_Gain
+} VideoProcAmpProperty;
+
+typedef long OAFilterState;
+typedef
+    enum tagAnalogVideoStandard { AnalogVideo_None = 0,
+    AnalogVideo_NTSC_M = 0x1,
+    AnalogVideo_NTSC_M_J = 0x2,
+    AnalogVideo_NTSC_433 = 0x4,
+    AnalogVideo_PAL_B = 0x10,
+    AnalogVideo_PAL_D = 0x20,
+    AnalogVideo_PAL_G = 0x40,
+    AnalogVideo_PAL_H = 0x80,
+    AnalogVideo_PAL_I = 0x100,
+    AnalogVideo_PAL_M = 0x200,
+    AnalogVideo_PAL_N = 0x400,
+    AnalogVideo_PAL_60 = 0x800,
+    AnalogVideo_SECAM_B = 0x1000,
+    AnalogVideo_SECAM_D = 0x2000,
+    AnalogVideo_SECAM_G = 0x4000,
+    AnalogVideo_SECAM_H = 0x8000,
+    AnalogVideo_SECAM_K = 0x10000,
+    AnalogVideo_SECAM_K1 = 0x20000,
+    AnalogVideo_SECAM_L = 0x40000,
+    AnalogVideo_SECAM_L1 = 0x80000
+} AnalogVideoStandard;
+
+
+typedef LONG_PTR OAHWND;
+typedef enum tagPhysicalConnectorType { PhysConn_Video_Tuner = 1,
+    PhysConn_Video_Composite = PhysConn_Video_Tuner + 1,
+    PhysConn_Video_SVideo = PhysConn_Video_Composite + 1,
+    PhysConn_Video_RGB = PhysConn_Video_SVideo + 1,
+    PhysConn_Video_YRYBY = PhysConn_Video_RGB + 1,
+    PhysConn_Video_SerialDigital = PhysConn_Video_YRYBY + 1,
+    PhysConn_Video_ParallelDigital = PhysConn_Video_SerialDigital + 1,
+    PhysConn_Video_SCSI = PhysConn_Video_ParallelDigital + 1,
+    PhysConn_Video_AUX = PhysConn_Video_SCSI + 1,
+    PhysConn_Video_1394 = PhysConn_Video_AUX + 1,
+    PhysConn_Video_USB = PhysConn_Video_1394 + 1,
+    PhysConn_Video_VideoDecoder = PhysConn_Video_USB + 1,
+    PhysConn_Video_VideoEncoder = PhysConn_Video_VideoDecoder + 1,
+    PhysConn_Video_SCART = PhysConn_Video_VideoEncoder + 1,
+    PhysConn_Video_Black = PhysConn_Video_SCART + 1,
+    PhysConn_Audio_Tuner = 0x1000,
+    PhysConn_Audio_Line = PhysConn_Audio_Tuner + 1,
+    PhysConn_Audio_Mic = PhysConn_Audio_Line + 1,
+    PhysConn_Audio_AESDigital = PhysConn_Audio_Mic + 1,
+    PhysConn_Audio_SPDIFDigital = PhysConn_Audio_AESDigital + 1,
+    PhysConn_Audio_SCSI = PhysConn_Audio_SPDIFDigital + 1,
+    PhysConn_Audio_AUX = PhysConn_Audio_SCSI + 1,
+    PhysConn_Audio_1394 = PhysConn_Audio_AUX + 1,
+    PhysConn_Audio_USB = PhysConn_Audio_1394 + 1,
+    PhysConn_Audio_AudioDecoder = PhysConn_Audio_USB + 1
+} PhysicalConnectorType;
+
+typedef struct _VIDEO_STREAM_CONFIG_CAPS {
+    GUID guid;			// will be MEDIATYPE_Video
+    ULONG VideoStandard;	// logical OR of all AnalogVideoStandards
+    // supported
+    SIZE InputSize;		// the inherent size of the incoming signal
+    // (every pixel unique)
+    SIZE MinCroppingSize;	// smallest rcSrc cropping rect allowed
+    SIZE MaxCroppingSize;	// largest rcSrc cropping rect allowed
+    int CropGranularityX;	// granularity of cropping size
+    int CropGranularityY;
+    int CropAlignX;		// alignment of cropping rect
+    int CropAlignY;
+    SIZE MinOutputSize;		// smallest bitmap stream can produce
+    SIZE MaxOutputSize;		// largest  bitmap stream can produce
+    int OutputGranularityX;	// granularity of output bitmap size
+    int OutputGranularityY;
+    int StretchTapsX;		// 0, no stretch, 1 pix dup, 2 interp, ...
+    int StretchTapsY;		//    Describes quality of hardware scaler
+    int ShrinkTapsX;		//
+    int ShrinkTapsY;		//
+    LONGLONG MinFrameInterval;	// 100 nS units
+    LONGLONG MaxFrameInterval;
+    LONG MinBitsPerSecond;
+    LONG MaxBitsPerSecond;
+} VIDEO_STREAM_CONFIG_CAPS, *PVIDEO_STREAM_CONFIG_CAPS;
+
+typedef struct _AUDIO_STREAM_CONFIG_CAPS {
+    GUID guid;
+    ULONG MinimumChannels;
+    ULONG MaximumChannels;
+    ULONG ChannelsGranularity;
+    ULONG MinimumBitsPerSample;
+    ULONG MaximumBitsPerSample;
+    ULONG BitsPerSampleGranularity;
+    ULONG MinimumSampleFrequency;
+    ULONG MaximumSampleFrequency;
+    ULONG SampleFrequencyGranularity;
+} AUDIO_STREAM_CONFIG_CAPS;
+
+typedef enum tagVideoProcAmpFlags {
+    VideoProcAmp_Flags_Auto = 0x0001,
+    VideoProcAmp_Flags_Manual = 0x0002
+} VideoProcAmpFlags;
+typedef enum {
+    PINDIR_INPUT = 0,
+    PINDIR_OUTPUT
+} PIN_DIRECTION;
+
+#define KSPROPERTY_SUPPORT_GET  1
+#define KSPROPERTY_SUPPORT_SET  2
+typedef struct {
+    GUID Set;
+    ULONG Id;
+    ULONG Flags;
+} KSIDENTIFIER;
+
+typedef KSIDENTIFIER KSPROPERTY;
+
+
+typedef struct {
+    KSPROPERTY Property;
+    ULONG Mode;			// IN: KSPROPERTY_TUNER_MODE
+    ULONG StandardsSupported;	// KS_AnalogVideo_* (if TV or DSS)
+    ULONG MinFrequency;		// Hz
+    ULONG MaxFrequency;		// Hz
+    ULONG TuningGranularity;	// Hz
+    ULONG NumberOfInputs;	// count of inputs
+    ULONG SettlingTime;		// milliSeconds
+    ULONG Strategy;		// KS_TUNER_STRATEGY
+} KSPROPERTY_TUNER_MODE_CAPS_S, *PKSPROPERTY_TUNER_MODE_CAPS_S;
+
+typedef struct {
+    KSPROPERTY Property;
+    ULONG Mode;			// IN: KSPROPERTY_TUNER_MODE
+} KSPROPERTY_TUNER_MODE_S, *PKSPROPERTY_TUNER_MODE_S;
+
+typedef struct {
+    KSPROPERTY Property;
+    ULONG Frequency;		// Hz
+    ULONG LastFrequency;	// Hz (last known good)
+    ULONG TuningFlags;		// KS_TUNER_TUNING_FLAGS
+    ULONG VideoSubChannel;	// DSS
+    ULONG AudioSubChannel;	// DSS
+    ULONG Channel;		// VBI decoders
+    ULONG Country;		// VBI decoders
+} KSPROPERTY_TUNER_FREQUENCY_S, *PKSPROPERTY_TUNER_FREQUENCY_S;
+typedef struct {
+    KSPROPERTY Property;
+    ULONG CurrentFrequency;
+    ULONG PLLOffset;
+    ULONG SignalStrength;
+    ULONG Busy;
+} KSPROPERTY_TUNER_STATUS_S, *PKSPROPERTY_TUNER_STATUS_S;
+typedef enum {
+    KS_TUNER_TUNING_EXACT = 1,	// No fine tuning
+    KS_TUNER_TUNING_FINE,	// Fine grained search
+    KS_TUNER_TUNING_COARSE,	// Coarse search
+} KS_TUNER_TUNING_FLAGS;
+
+typedef enum {
+    KSPROPERTY_TUNER_CAPS,	// R  -overall device capabilities
+    KSPROPERTY_TUNER_MODE_CAPS,	// R  -capabilities in this mode
+    KSPROPERTY_TUNER_MODE,	// RW -set a mode (TV, FM, AM, DSS)
+    KSPROPERTY_TUNER_STANDARD,	// R  -get TV standard (only if TV mode)
+    KSPROPERTY_TUNER_FREQUENCY,	// RW -set/get frequency
+    KSPROPERTY_TUNER_INPUT,	// RW -select an input
+    KSPROPERTY_TUNER_STATUS,	// R  -tuning status
+    KSPROPERTY_TUNER_IF_MEDIUM	// R O-Medium for IF or Transport Pin
+} KSPROPERTY_TUNER;
+typedef enum {
+    KS_TUNER_STRATEGY_PLL = 0X01,	// Tune by PLL offset
+    KS_TUNER_STRATEGY_SIGNAL_STRENGTH = 0X02,	// Tune by signal strength
+    KS_TUNER_STRATEGY_DRIVER_TUNES = 0X04,	// Driver does fine tuning
+} KS_TUNER_STRATEGY;
+typedef enum tagTVAudioMode {
+    AMTVAUDIO_MODE_MONO = 0x0001,
+    AMTVAUDIO_MODE_STEREO = 0x0002,
+    AMTVAUDIO_MODE_LANG_A = 0x0010,
+    AMTVAUDIO_MODE_LANG_B = 0x0020,
+    AMTVAUDIO_MODE_LANG_C = 0x0040,
+} TVAudioMode;
+
+typedef struct _FilterInfo {
+    WCHAR achName[128];
+    LPFILTERGRAPH pGraph;
+} FILTER_INFO;
+
+typedef struct _PinInfo {
+    LPBASEFILTER pFilter;
+    PIN_DIRECTION dir;
+    unsigned short achName[128];
+} PIN_INFO;
+//-----------------------------------
+
+
+#undef INTERFACE
+#define INTERFACE IPin
+DECLARE_INTERFACE(IPin)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(Connect) (THIS_ IPin *, AM_MEDIA_TYPE *);
+    STDMETHOD(ReceiveConnection) (THIS_ IPin *, const AM_MEDIA_TYPE *);
+    STDMETHOD(Disconnect) (THIS);
+    STDMETHOD(ConnectedTo) (THIS_ IPin **);
+    STDMETHOD(ConnectionMediaType) (THIS_ AM_MEDIA_TYPE * pmt);
+    STDMETHOD(QueryPinInfo) (THIS_ PIN_INFO *);
+    STDMETHOD(QueryDirection) (THIS_ PIN_DIRECTION *);
+    STDMETHOD(QueryId) (THIS_ unsigned short **);
+    STDMETHOD(QueryAccept) (THIS_ const AM_MEDIA_TYPE *);
+    STDMETHOD(EnumMediaTypes) (THIS_ LPENUMMEDIATYPES *);
+    STDMETHOD(QueryInternalConnections) (THIS_ IPin **, unsigned long *);
+    STDMETHOD(EndOfStream) (THIS);
+    STDMETHOD(BeginFlush) (THIS);
+    STDMETHOD(EndFlush) (THIS);
+    STDMETHOD(NewSegment) (THIS_ REFERENCE_TIME, REFERENCE_TIME, double);
+};
+
+#undef INTERFACE
+#define INTERFACE IBaseFilter
+DECLARE_INTERFACE(IBaseFilter)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(GetClassID) (THIS_ CLSID * pClassID);
+    STDMETHOD(Stop) (THIS);
+    STDMETHOD(Pause) (THIS);
+    STDMETHOD(Run) (THIS_ REFERENCE_TIME tStart);
+    STDMETHOD(GetState) (THIS_ unsigned long, void *);
+    STDMETHOD(SetSyncSource) (THIS_ LPREFERENCECLOCK);
+    STDMETHOD(GetSyncSource) (THIS_ LPREFERENCECLOCK *);
+    STDMETHOD(EnumPins) (THIS_ LPENUMPINS *);
+    STDMETHOD(FindPin) (THIS_ const unsigned short *, LPPIN *);
+    STDMETHOD(QueryFilterInfo) (THIS_ void *);
+    STDMETHOD(JoinFilterGraph) (THIS_ LPFILTERGRAPH,
+				const unsigned short *);
+    STDMETHOD(QueryVendorInfo) (THIS_ unsigned short **);
+};
+
+#undef INTERFACE
+#define INTERFACE IAMTVTuner
+DECLARE_INTERFACE(IAMTVTuner)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(put_Channel) (THIS_ long, long, long);
+    STDMETHOD(get_Channel) (THIS_ long *, long *, long *);
+    STDMETHOD(ChannelMinMax) (THIS_ long *, long *);
+    STDMETHOD(put_CountryCode) (THIS_ long);
+    STDMETHOD(get_CountryCode) (THIS_ long *);
+    STDMETHOD(put_TuningSpace) (THIS_ long);
+    STDMETHOD(get_TuningSpace) (THIS_ long *);
+    STDMETHOD(Logon) (THIS_ HANDLE);
+    STDMETHOD(Logout) (IAMTVTuner *);
+    STDMETHOD(SignalPresen) (THIS_ long *);
+    STDMETHOD(put_Mode) (THIS_ AMTunerModeType);
+    STDMETHOD(get_Mode) (THIS_ AMTunerModeType *);
+    STDMETHOD(GetAvailableModes) (THIS_ long *);
+    STDMETHOD(RegisterNotificationCallBack) (THIS_ LPAMTUNERNOTIFICATION,
+					     long);
+    STDMETHOD(UnRegisterNotificationCallBack) (THIS_
+					       LPAMTUNERNOTIFICATION);
+    STDMETHOD(get_AvailableTVFormats) (THIS_ long *);
+    STDMETHOD(get_TVFormat) (THIS_ long *);
+    STDMETHOD(AutoTune) (THIS_ long, long *);
+    STDMETHOD(StoreAutoTune) (IAMTVTuner *);
+    STDMETHOD(get_NumInputConnections) (THIS_ long *);
+    STDMETHOD(put_InputType) (THIS_ long, TunerInputType);
+    STDMETHOD(get_InputType) (THIS_ long, TunerInputType *);
+    STDMETHOD(put_ConnectInput) (THIS_ long);
+    STDMETHOD(get_ConnectInput) (THIS_ long *);
+    STDMETHOD(get_VideoFrequency) (THIS_ long *);
+    STDMETHOD(get_AudioFrequency) (THIS_ long *);
+};
+
+#undef INTERFACE
+#define INTERFACE IMediaControl
+DECLARE_INTERFACE(IMediaControl)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(GetTypeInfoCount) (THIS_ UINT *);
+    STDMETHOD(GetTypeInfo) (THIS_ UINT, LCID, LPTYPEINFO *);
+    STDMETHOD(GetIDsOfNames) (THIS_ REFIID, LPOLESTR *, UINT, LCID,
+			      DISPID *);
+    STDMETHOD(Invoke) (THIS_ DISPID, REFIID, LCID, WORD, LPDISPPARAMS,
+		       VARIANT *, EXCEPINFO *, UINT *);
+    STDMETHOD(Run) (THIS);
+    STDMETHOD(Pause) (THIS);
+    STDMETHOD(Stop) (THIS);
+    STDMETHOD(GetState) (THIS_ LONG, OAFilterState *);
+    STDMETHOD(RenderFile) (THIS_ BSTR);
+    STDMETHOD(AddSourceFilter) (THIS_ BSTR, LPDISPATCH *);
+    STDMETHOD(get_FilterCollection) (THIS_ LPDISPATCH *);
+    STDMETHOD(get_RegFilterCollection) (THIS_ LPDISPATCH *);
+    STDMETHOD(StopWhenReady) (IMediaControl *);
+};
+
+#undef INTERFACE
+#define INTERFACE IGraphBuilder
+DECLARE_INTERFACE(IGraphBuilder)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(AddFilter) (THIS_ IBaseFilter *, LPCWSTR);
+    STDMETHOD(RemoveFilter) (THIS_ IBaseFilter *);
+    STDMETHOD(EnumFilters) (THIS_ LPENUMFILTERS *);
+    STDMETHOD(FindFilterByName) (THIS_ LPCWSTR, IBaseFilter **);
+    STDMETHOD(ConnectDirect) (THIS_ IPin *, IPin *, const AM_MEDIA_TYPE *);
+    STDMETHOD(Reconnect) (THIS_ IPin *);
+    STDMETHOD(Disconnect) (THIS_ IPin *);
+    STDMETHOD(SetDefaultSyncSource) (IGraphBuilder *);
+    STDMETHOD(Connect) (THIS_ IPin *, IPin *);
+    STDMETHOD(Render) (THIS_ IPin *);
+    STDMETHOD(RenderFile) (THIS_ LPCWSTR, LPCWSTR);
+    STDMETHOD(AddSourceFilter) (THIS_ LPCWSTR, LPCWSTR, IBaseFilter **);
+    STDMETHOD(SetLogFile) (THIS_ DWORD_PTR);
+    STDMETHOD(Abort) (IGraphBuilder *);
+    STDMETHOD(ShouldOperationContinue) (IGraphBuilder *);
+};
+
+
+#undef INTERFACE
+#define INTERFACE ICaptureGraphBuilder2
+DECLARE_INTERFACE(ICaptureGraphBuilder2)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(SetFiltergraph) (THIS_ IGraphBuilder *);
+    STDMETHOD(GetFiltergraph) (THIS_ IGraphBuilder **);
+    STDMETHOD(SetOutputFileName) (THIS_ const GUID *, LPCOLESTR,
+				  IBaseFilter **, LPFILESINKFILTER *);
+    STDMETHOD(FindInterface) (THIS_ const GUID *, const GUID *,
+			      IBaseFilter *, REFIID, void **);
+    STDMETHOD(RenderStream) (THIS_ const GUID *, const GUID *, IUnknown *,
+			     IBaseFilter *, IBaseFilter *);
+    STDMETHOD(ControlStream) (THIS_ const GUID *, const GUID *,
+			      IBaseFilter *, REFERENCE_TIME *,
+			      REFERENCE_TIME *, WORD, WORD);
+    STDMETHOD(AllocCapFile) (THIS_ LPCOLESTR, DWORDLONG);
+    STDMETHOD(CopyCaptureFile) (THIS_ LPOLESTR, LPOLESTR, int,
+				LPAMCOPYCAPTUREFILEPROGRESS);
+    STDMETHOD(FindPin) (THIS_ IUnknown *, PIN_DIRECTION, const GUID *,
+			const GUID *, BOOL, int, IPin **);
+};
+
+#undef INTERFACE
+#define INTERFACE ICreateDevEnum
+DECLARE_INTERFACE(ICreateDevEnum)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(CreateClassEnumerator) (THIS_ REFCLSID, IEnumMoniker **,
+				      DWORD);
+};
+
+#undef INTERFACE
+#define INTERFACE IAMCrossbar
+DECLARE_INTERFACE(IAMCrossbar)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(get_PinCounts) (THIS_ long *, long *);
+    STDMETHOD(CanRoute) (THIS_ long, long);
+    STDMETHOD(Route) (THIS_ long, long);
+    STDMETHOD(get_IsRoutedTo) (THIS_ long, long *);
+    STDMETHOD(get_CrossbarPinInfo) (THIS_ BOOL, long, long *, long *);
+};
+
+#undef INTERFACE
+#define INTERFACE IPropertyBag
+DECLARE_INTERFACE(IPropertyBag)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(Read) (THIS_ LPCOLESTR, LPVARIANT, LPERRORLOG);
+    STDMETHOD(Write) (THIS_ LPCOLESTR, LPVARIANT);
+};
+
+#undef INTERFACE
+#define INTERFACE IAMStreamConfig
+DECLARE_INTERFACE(IAMStreamConfig)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    HRESULT(STDMETHODCALLTYPE * SetFormat) (THIS_ AM_MEDIA_TYPE *);
+    HRESULT(STDMETHODCALLTYPE * GetFormat) (THIS_ AM_MEDIA_TYPE **);
+    HRESULT(STDMETHODCALLTYPE * GetNumberOfCapabilities) (THIS_ int *,int *);
+    HRESULT(STDMETHODCALLTYPE * GetStreamCaps) (THIS_ int,AM_MEDIA_TYPE **, BYTE *);
+};
+
+#undef INTERFACE
+#define INTERFACE IAMVideoProcAmp
+DECLARE_INTERFACE(IAMVideoProcAmp)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(GetRange) (THIS_ long, long *, long *, long *, long *,long *);
+    STDMETHOD(Set) (THIS_ long, long, long);
+    STDMETHOD(Get) (THIS_ long, long *, long *);
+};
+
+#undef INTERFACE
+#define INTERFACE IKsPropertySet
+DECLARE_INTERFACE(IKsPropertySet)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    HRESULT(STDMETHODCALLTYPE * Set) (THIS_ REFGUID, DWORD, LPVOID, DWORD,LPVOID, DWORD);
+    HRESULT(STDMETHODCALLTYPE * Get) (THIS_ REFGUID, DWORD, LPVOID, DWORD,LPVOID, DWORD, DWORD *);
+    HRESULT(STDMETHODCALLTYPE * QuerySupported) (THIS_ REFGUID, DWORD,DWORD *);
+};
+
+#undef INTERFACE
+#define INTERFACE IAMAnalogVideoDecoder
+DECLARE_INTERFACE(IAMAnalogVideoDecoder)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(get_AvailableTVFormats) (THIS_ long *);
+    STDMETHOD(put_TVFormat) (THIS_ long);
+    STDMETHOD(get_TVFormat) (THIS_ long *);
+    STDMETHOD(get_HorizontalLocked) (THIS_ long *);
+    STDMETHOD(put_VCRHorizontalLocking) (THIS_ long);
+    STDMETHOD(get_VCRHorizontalLocking) (THIS_ long *);
+    STDMETHOD(get_NumberOfLines) (THIS_ long *);
+    STDMETHOD(put_OutputEnable) (THIS_ long);
+    STDMETHOD(get_OutputEnable) (THIS_ long *);
+};
+
+#undef INTERFACE
+#define INTERFACE IAMTVAudio
+DECLARE_INTERFACE(IAMTVAudio)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(GetHardwareSupportedTVAudioModes) (THIS_ long *);
+    STDMETHOD(GetAvailableTVAudioModes) (THIS_ long *);
+    STDMETHOD(get_TVAudioMode) (THIS_ long *);
+    STDMETHOD(put_TVAudioMode) (THIS_ long);
+    STDMETHOD(RegisterNotificationCallBack) (THIS_ LPAMTUNERNOTIFICATION,
+					     long);
+    STDMETHOD(UnRegisterNotificationCallBack) (THIS_
+					       LPAMTUNERNOTIFICATION);
+};
+
+
+#undef INTERFACE
+#define INTERFACE ISampleGrabberCB
+DECLARE_INTERFACE(ISampleGrabberCB)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(SampleCB) (THIS_ double, LPMEDIASAMPLE);
+    STDMETHOD(BufferCB) (THIS_ double, BYTE *, long);
+};
+
+#undef INTERFACE
+#define INTERFACE ISampleGrabber
+DECLARE_INTERFACE(ISampleGrabber)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(SetOneShot) (THIS_ BOOL);
+    STDMETHOD(SetMediaType) (THIS_ const AM_MEDIA_TYPE *);
+    STDMETHOD(GetConnectedMediaType) (THIS_ AM_MEDIA_TYPE *);
+    STDMETHOD(SetBufferSamples) (THIS_ BOOL);
+    STDMETHOD(GetCurrentBuffer) (THIS_ long *, long *);
+    STDMETHOD(GetCurrentSample) (THIS_ LPMEDIASAMPLE *);
+    STDMETHOD(SetCallback) (THIS_ ISampleGrabberCB *, long);
+};
+
+#undef INTERFACE
+#define INTERFACE IFilterGraph
+DECLARE_INTERFACE(IFilterGraph)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(AddFilter) (THIS_ LPBASEFILTER, LPCWSTR);
+    STDMETHOD(RemoveFilter) (THIS_ LPBASEFILTER);
+    STDMETHOD(EnumFilters) (THIS_ LPENUMFILTERS *);
+    STDMETHOD(FindFilterByName) (THIS_ LPCWSTR, LPBASEFILTER *);
+    STDMETHOD(ConnectDirect) (THIS_ IPin *, IPin *, const AM_MEDIA_TYPE *);
+    STDMETHOD(Reconnect) (THIS_ LPPIN);
+    STDMETHOD(Disconnect) (THIS_ LPPIN);
+    STDMETHOD(SetDefaultSyncSource) (THIS);
+};
+
+#undef INTERFACE
+#define INTERFACE IAMAudioInputMixer
+DECLARE_INTERFACE(IAMAudioInputMixer)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(put_Enable) (THIS_ BOOL);
+    STDMETHOD(get_Enable) (THIS_ BOOL *);
+    STDMETHOD(put_Mono) (THIS_ BOOL);
+    STDMETHOD(get_Mono) (THIS_ BOOL *);
+    STDMETHOD(put_MixLevel) (THIS_ double);
+    STDMETHOD(get_MixLevel) (THIS_ double *);
+    STDMETHOD(put_Pan) (THIS_ double);
+    STDMETHOD(get_Pan) (THIS_ double *);
+    STDMETHOD(put_Loudness) (THIS_ BOOL);
+    STDMETHOD(get_Loudness) (THIS_ BOOL *);
+    STDMETHOD(put_Treble) (THIS_ double);
+    STDMETHOD(get_Treble) (THIS_ double *);
+    STDMETHOD(get_TrebleRange) (THIS_ double *);
+    STDMETHOD(put_Bass) (THIS_ double);
+    STDMETHOD(get_Bass) (THIS_ double *);
+    STDMETHOD(get_BassRange) (THIS_ double *);
+};
+
+
+#undef INTERFACE
+#define INTERFACE IMediaSample
+DECLARE_INTERFACE(IMediaSample)
+{
+    STDMETHOD(QueryInterface) (THIS_ const GUID *, void **);
+    STDMETHOD_(long, AddRef) (THIS);
+    STDMETHOD_(long, Release) (THIS);
+    STDMETHOD(GetPointer )(THIS_ unsigned char** );
+    STDMETHOD_(LONG,GetSize )(THIS);
+    STDMETHOD(GetTime )(THIS_ REFERENCE_TIME* ,REFERENCE_TIME* );
+    STDMETHOD(SetTime )(THIS_ REFERENCE_TIME* ,REFERENCE_TIME* );
+    STDMETHOD(IsSyncPoint )(THIS);
+    STDMETHOD(SetSyncPoint )(THIS_ long );
+    STDMETHOD(IsPreroll )(THIS);
+    STDMETHOD(SetPreroll )(THIS_ long );
+    STDMETHOD_(LONG,GetActualDataLength)(THIS);
+    STDMETHOD(SetActualDataLength )(THIS_ long );
+    STDMETHOD(GetMediaType )(THIS_ AM_MEDIA_TYPE** );
+    STDMETHOD(SetMediaType )(THIS_ AM_MEDIA_TYPE* );
+    STDMETHOD(IsDiscontinuity )(THIS);
+    STDMETHOD(SetDiscontinuity )(THIS_ long );
+    STDMETHOD(GetMediaTime )(THIS_ long long* ,long long* );
+    STDMETHOD(SetMediaTime )(THIS_ long long* ,long long* );
+};
+
+    
+#undef INTERFACE
+#define INTERFACE IAMBufferNegotiation
+DECLARE_INTERFACE(IAMBufferNegotiation)
+{
+    STDMETHOD(QueryInterface )(THIS_ REFIID ,void **);
+    STDMETHOD_(ULONG,AddRef )(THIS);
+    STDMETHOD_(ULONG,Release )(THIS);
+    STDMETHOD(SuggestAllocatorProperties )(THIS_ const ALLOCATOR_PROPERTIES *);
+    STDMETHOD(GetAllocatorProperties )(THIS_ ALLOCATOR_PROPERTIES *);
+};
+
+
+#undef INTERFACE
+#define INTERFACE IVideoWindow
+DECLARE_INTERFACE(IVideoWindow)
+{
+    STDMETHOD(QueryInterface )(THIS_ REFIID ,void **);
+    STDMETHOD_(ULONG,AddRef )(THIS);
+    STDMETHOD_(ULONG,Release )(THIS);
+    STDMETHOD(GetTypeInfoCount) (THIS_ UINT * );
+    STDMETHOD(GetTypeInfo) (THIS_  UINT ,LCID , ITypeInfo ** );
+    STDMETHOD(GetIDsOfNames) (THIS_  REFIID ,LPOLESTR * , UINT ,LCID , DISPID * );
+    STDMETHOD(Invoke) (THIS_  DISPID ,REFIID , LCID , WORD ,void *, VARIANT * ,EXCEPINFO * , UINT * );
+    STDMETHOD(put_Caption) (THIS_  BSTR );
+    STDMETHOD(get_Caption) (THIS_  BSTR * );
+    STDMETHOD(put_WindowStyle) (THIS_ long );
+    STDMETHOD(get_WindowStyle) (THIS_ long *);
+    STDMETHOD(put_WindowStyleEx) (THIS_ long );
+    STDMETHOD(get_WindowStyleEx) (THIS_ long *);
+    STDMETHOD(put_AutoShow) (THIS_  long );
+    STDMETHOD(get_AutoShow) (THIS_  long *);
+    STDMETHOD(put_WindowState) (THIS_ long );
+    STDMETHOD(get_WindowState) (THIS_ long *);
+    STDMETHOD(put_BackgroundPalette) (THIS_ long );
+    STDMETHOD(get_BackgroundPalette) (THIS_ long *);
+    STDMETHOD(put_Visible) (THIS_  long );
+    STDMETHOD(get_Visible) (THIS_  long *);
+    STDMETHOD(put_Left) (THIS_  long );
+    STDMETHOD(get_Left) (THIS_  long *);
+    STDMETHOD(put_Width) (THIS_  long );
+    STDMETHOD(get_Width) (THIS_  long *);
+    STDMETHOD(put_Top) (THIS_  long );
+    STDMETHOD(get_Top) (THIS_  long *);
+    STDMETHOD(put_Height) (THIS_  long );
+    STDMETHOD(get_Height) (THIS_  long *);
+    STDMETHOD(put_Owner) (THIS_  OAHWND );
+    STDMETHOD(get_Owner) (THIS_  OAHWND * );
+    STDMETHOD(put_MessageDrain) (THIS_  OAHWND );
+    STDMETHOD(get_MessageDrain) (THIS_ OAHWND * );
+    STDMETHOD(get_BorderColor) (THIS_  long *);
+    STDMETHOD(put_BorderColor) (THIS_  long );
+    STDMETHOD(get_FullScreenMode) (THIS_ long *);
+    STDMETHOD(put_FullScreenMode) (THIS_ long );
+    STDMETHOD(SetWindowForeground) (THIS_ long );
+    STDMETHOD(NotifyOwnerMessage) (THIS_  OAHWND ,long , LONG_PTR ,LONG_PTR );
+    STDMETHOD(SetWindowPosition) (THIS_  long ,long , long ,long );
+    STDMETHOD(GetWindowPosition) (THIS_  long *,long *, long *,long *);
+    STDMETHOD(GetMinIdealImageSize) (THIS_ long *, long *);
+    STDMETHOD(GetMaxIdealImageSize) (THIS_ long *, long *);
+    STDMETHOD(GetRestorePosition) (THIS_  long *,long *, long *,long *);
+    STDMETHOD(HideCursor) (THIS_  long );
+    STDMETHOD(IsCursorHidden) (THIS_ long *);
+};
+
+DECLARE_ENUMERATOR_(IEnumFilters, LPBASEFILTER);
+DECLARE_ENUMERATOR_(IEnumPins, LPPIN);
+DECLARE_ENUMERATOR_(IEnumMediaTypes, AM_MEDIA_TYPE *);
+
+#define OLE_CALL(p,method)               (p)->lpVtbl->method(p)
+#ifdef __GNUC__
+#define OLE_CALL_ARGS(p, method, a1, args...) (p)->lpVtbl->method(p, a1, ##args)
+#else
+#define OLE_CALL_ARGS(p, method, ...) (p)->lpVtbl->method(p, __VA_ARGS__)
+#endif
+#define OLE_RELEASE_SAFE(p) if(p){ OLE_CALL((IUnknown*)p,Release); p=NULL;}
+#define OLE_QUERYINTERFACE(p,iface,ptr) OLE_CALL_ARGS((IUnknown*)p,QueryInterface,&iface,(void*)&ptr)
+
+#endif	// TVI_DSHOW_H_