[MPlayer-dev-eng] [RFC] TV support under Win32 using DirectShow

Vladimir Voroshilov voroshil at gmail.com
Tue Jan 16 21:24:28 CET 2007


2007/1/17, Reimar Döffinger <Reimar.Doeffinger at stud.uni-karlsruhe.de>:
> Hello,
> On Tue, Jan 16, 2007 at 02:16:41PM +0600, Vladimir Voroshilov wrote:
> > Driver consist of two parts:
> > 1. DirectShow  filter with one video and one audio input pin to grab
> > media samples from live source (almost finished)
>
> I strongly prefer solutions that do not require installation if that was
> possible.
It does need any installation.I meant that one part of my code acts as
DirectShow filter, by i did not say that it is full-featured
DirectShow filter's DLL. My driver  is part of MPlayer. MPlayer will
build filter (as DirectShow object) at  runtime while opening tv://
under Win32.

> >   * Pausing or moving video windows causes buffer overflow (no pause
> > callback exists for tv subsystem in MPlayer and i'm afraid the same
> > issue can be  applyed to the linux TV code).
>
> Will have to see about that in detail, but in principle the stream layer
> can just drop frames, assuming it knows where frames start and end...
> I'm fairly certain that should be fixable (though even nicer would be if
> moving the window wouldn't stop everything - interestingly the same
> issue exists under linux, but only with some window managers...)
I'll continue to investigate it.

> >   * Sets channels only by it's number, not by freq (probably device
> > driver's limitation) that requires some not fine workaround.
>
> "not fine" meaning? A table for translating frequencies into channels
> seems like a perfectly fine way to handle this.
> Anyway, without seeing the real code it all is hard to say...
But used IAMTVTuner Directshow interface doesn't  allow to set
frequency, just channel number. Thus i have to read DirectShow's
channel table first for proper country (not implemented yet), and
every time translate given by tv.c frequency into channel number. This
is what i meant under "not fine workaround". I am planning to do
following:
1. try to set frequency using IKsPropertySet (direct call to tuner, i
think, but not sure).
2. if first call fails driver will set up some flag and will use 3
instead this method until MPlayer finished.
3 driver will use workaround described above.

> > If anybody will be interesting in testing it i can upload prebuilded
> > binaries+source anywhere in Web to make testing more easy.
>
> This is the developers list, I'm sure some here would prefer not to test even
> their own patches. If you want testing, MPlayer-cygwin or so seems the
> better place to suggest it...
:) ok.

Well, i have attached current development version.
First i want hear something about driver's architecture.
Probably i am running in wrong way (i hope, I'm not).

I'm afraid that (due to output.c changes) it can also broke any
functionality in Win32 loader (it shouldn't but who knows...). I have
tested (under Linux) all media files from my HDD, but non of them used
dshow loader (just dmo). Thus my test was incomplete.

I also does not decide where put tvi_dshow.h contents to.
It contains some declaration, that already defined in either recent
wine versions or used mingw32. Unfortunately it is not possible to mix
it together.

-- 
Regards,
Vladimir Voroshilov     mailto:voroshil at gmail.com
JID: voroshil at jabber.ru
ICQ: 95587719
-------------- next part --------------
Index: configure
===================================================================
--- configure	(revision 21934)
+++ configure	(working copy)
@@ -1721,6 +1721,7 @@
 _tv_v4l1=auto
 _tv_v4l2=auto
 _tv_bsdbt848=auto
+_tv_dshow=auto
 _pvr=auto
 _network=yes
 _winsock2=auto
@@ -1971,6 +1972,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-radio)       _radio=yes	;;
   --enable-radio-capture)       _radio_capture=yes	;;
   --disable-radio-capture)       _radio_capture=no	;;
@@ -6692,6 +6695,33 @@
 fi #if bsd
 
 
+echocheck "DirectShow TV interface"
+if test "$_tv_dshow" = auto ; then
+ _tv_dshow=no
+ if test "$_tv" = yes && mingw32 ; then
+  cat > $TMPC <<EOF
+#include <basetyps.h>
+int main(void) { 
+    void* p;
+    CoCreateInstance((GUID*)&GUID_NULL, NULL, CLSCTX_INPROC_SERVER, &GUID_NULL, (void**)&p);
+    return 0; 
+}
+EOF
+  cc_check && _tv_dshow=yes
+ fi
+fi
+if test "$_tv_dshow" = yes ; then
+  _tv_v4l=yes
+  _def_tv_v4l='#define HAVE_TV_DSHOW 1'
+  _def_tv_v4l1='#define HAVE_TV_DSHOW 1'
+  _inputmodules="tv-dshow $_inputmodules"
+else
+  _noinputmodules="tv-dshow $_noinputmodules"
+  _def_tv_v4l='#undef HAVE_TV_DSHOW'
+fi
+echores "$_tv_dshow"
+
+
 echocheck "Video 4 Linux TV interface"
 if test "$_tv_v4l1" = auto ; then
  _tv_v4l1=no
@@ -7526,6 +7556,7 @@
 TV_V4L  = $_tv_v4l
 TV_V4L1 = $_tv_v4l1
 TV_V4L2 = $_tv_v4l2
+TV_DSHOW = $_tv_dshow
 TV_BSDBT848 = $_tv_bsdbt848
 PVR = $_pvr
 VCD = $_vcd
@@ -8040,6 +8071,9 @@
 /* Enable Video 4 Linux 2 TV interface support */
 $_def_tv_v4l2
 
+/* Enable DirectShow TV interface support */
+$_def_tv_dshow
+
 /* Enable *BSD BrookTree TV interface support */
 $_def_tv_bsdbt848
 
Index: loader/com.h
===================================================================
--- loader/com.h	(revision 21934)
+++ loader/com.h	(working copy)
@@ -25,8 +25,6 @@
 extern "C" {
 #endif
 
-void* CoTaskMemAlloc(unsigned long cb);
-void CoTaskMemFree(void* cb);
 
 #ifndef GUID_TYPE
 #define GUID_TYPE
@@ -77,8 +75,18 @@
     struct IClassFactory_vt* vt;
 };
 
+#if !defined(__MINGW32__) 
+//need proper ifdef to check Co* functions availability 
 long CoCreateInstance(GUID* rclsid, struct IUnknown* pUnkOuter,
 		      long dwClsContext, const GUID* riid, void** ppv);
+void* CoTaskMemAlloc(unsigned long cb);
+void CoTaskMemFree(void* cb);
+#else
+long STDCALL CoCreateInstance(GUID* rclsid, struct IUnknown* pUnkOuter,
+		      long dwClsContext, const GUID* riid, void** ppv);
+void* STDCALL  CoTaskMemAlloc(unsigned long);
+void  STDCALL  CoTaskMemFree(void*);
+#endif
 
 #ifdef __cplusplus
 };
Index: loader/dshow/DS_Filter.c
===================================================================
--- loader/dshow/DS_Filter.c	(revision 21934)
+++ loader/dshow/DS_Filter.c	(working copy)
@@ -249,7 +249,7 @@
             break;
 	}
 
-	This->m_pOurOutput = COutputPinCreate(This->m_pDestType);
+	This->m_pOurOutput = COutputPinCreate(This->m_pDestType,(IBaseFilter*)This);
 
 	result = This->m_pOutputPin->vt->ReceiveConnection(This->m_pOutputPin,
 							   (IPin*) This->m_pOurOutput,
Index: loader/dshow/DS_MPGrabber.c
===================================================================
--- loader/dshow/DS_MPGrabber.c	(revision 0)
+++ loader/dshow/DS_MPGrabber.c	(revision 0)
@@ -0,0 +1,730 @@
+#include "DS_MPGrabber.h"
+#include "wine/winerror.h"
+#include "outputpin.h"
+#include "inputpin.h"
+#include "interfaces.h"
+
+#include <stdlib.h>
+#include "mp_msg.h"
+
+
+#ifndef NOAVIFILE_HEADERS
+#include "audiodecoder.h"
+#include "except.h"
+#define VFW_E_NOT_RUNNING               0x80040226
+#define VFW_E_NO_ALLOCATOR              0x8004020A
+//#include "fourcc.h"
+//#include "except.h"
+#else
+#include "libwin32.h"
+#endif
+
+#define Debug if(0)
+
+const GUID IID_IAMFilterMiscFlags={0x2dd74950, 0xa890, 0x11d1,
+    { 0xab, 0xe8, 0x00, 0xa0, 0xc9, 0x05, 0xf3, 0x75}};
+
+const GUID IID_IPersist={0x0000010c,0x0000,0x0000,
+    { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
+
+static inline int unimplemented(const char* s, void* p)
+{
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"%s(%p) called (UNIMPLEMENTED)\n", s, p);
+    return E_NOTIMPL;
+}
+
+//FIXME: need a real GUID
+const CLSID CLSID_MPGrabber={0x12345678,0x4643,0x0654,
+    { 0x05, 0xc3, 0x02, 0x50, 0x05, 0x20, 0x30, 0x46}};
+
+/**
+ Implementation of IAMFilterMiscFlags interface
+ 
+ Used to point filter graph that our filter is Renderer
+ TODO: check if this really need
+ 
+*/
+typedef struct CAMFilterMiscFlags{
+    IAMFilterMiscFlags_vt* vt;
+    DECLARE_IUNKNOWN();
+    GUID interfaces[2];
+
+    ULONG flags;
+} CAMFilterMiscFlags;
+
+
+/**
+ * \brief IAMFilterMiscFlags::GetMiscFlags
+ *
+ * \param[in] this IAMFilterMiscFlags interface
+ *
+ * \return flags
+ */
+static ULONG STDCALL CAMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags* This)
+{
+  return ((CAMFilterMiscFlags*)This)->flags;
+}
+
+/**
+ * \brief CAMFilterMiscFlags destructor
+ *
+ * \param[in] this IAMFilterMiscFlags interface
+ *
+ */
+void CAMFilterMiscFlags_Destroy(CAMFilterMiscFlags* This){
+    if (This->vt)
+	free(This->vt);
+    free(This);
+}
+
+IMPLEMENT_IUNKNOWN(CAMFilterMiscFlags)
+
+
+/**
+ * \brief CAMFilterMiscFlags constructor
+ *
+ * \param[in] this IAMFilterMiscFlags interface
+ * \param[in] flags flags to return with IAMFilterMiscFlags::GetMiscFlags
+ *
+ * \return CAMFilterMiscFlags object pointer
+ * \return NULL if error occured
+ *
+ */
+CAMFilterMiscFlags* CAMFilterMiscFlagsCreate(ULONG flags){
+    CAMFilterMiscFlags* This = (CAMFilterMiscFlags*) malloc(sizeof(CAMFilterMiscFlags));
+    if (!This)
+	return NULL;
+    This->vt = (IBaseFilter_vt*) malloc(sizeof(IBaseFilter_vt));
+
+    if (!This->vt)
+    {
+        CAMFilterMiscFlags_Destroy(This);
+        return NULL;
+    }
+
+    This->refcount = 1;
+    This->flags=flags;
+    This->vt->QueryInterface = CAMFilterMiscFlags_QueryInterface;
+    This->vt->AddRef = CAMFilterMiscFlags_AddRef;
+    This->vt->Release = CAMFilterMiscFlags_Release;
+
+    This->interfaces[0] = IID_IUnknown;
+    This->interfaces[1] = IID_IAMFilterMiscFlags;
+
+    This->vt->GetMiscFlags = CAMFilterMiscFlags_GetMiscFlags;
+    return This;
+}
+
+/*******************************************
+ *  Implementation of DS_MPGrabber methods
+ ********************************************/
+
+/**
+ * \brief fills given buffer with data of next media sample
+ *
+ * \param[in] This pointer to DS_MPGrabber object
+ * \param[out] buf pointer to buffer
+ * \param[in] len buffer length
+ * \param[in] bVideo 1-video sample,0-audio sample
+ * \param[in] pPts address of variable receives timestamp
+ *
+ * \return number of data written to buffer
+ *
+ */
+static int STDCALL DS_Grabber_FillBuffer(DS_MPGrabber* This,char* buf,int len,int bVideo,long long * pPts){
+    IMediaSample* sample;
+    IMemAllocator* pAll=NULL;
+    HRESULT hr;
+    int i,bytes=0;
+    BYTE* pBuffer=NULL;
+    COutputPin* pin=NULL;
+
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber_FillBuffer (%p,%d)\n", This,bVideo);
+
+
+    if (bVideo)
+        pin=This->pinVideo;
+    else
+        pin=This->pinAudio;
+
+    if(!pin) return 0; //No required byffer    
+    for(i=0;i<100 && !bytes;i++)
+    {
+        bytes=pin->FillBuffer(pin,buf,len,pPts,NULL);
+        if(bytes) break;
+        sleep(1);
+    }
+    return bytes;
+}
+
+/**
+ * \brief IPersist::GetClassID (returns filter's CLSID)
+ *
+ * \param[in] this pointer to IPersis interface
+ * \param[out] pClassID address of CLSID variables that receives Filter's class id
+ *
+ * \return E_POINTER Null pointer
+ * \return S_OK success
+ * \return E_FAIL error occured
+ *
+ * stub
+ *
+ */
+static long STDCALL DS_MPGrabber_GetClassID(IBaseFilter * This, CLSID *pClassID)
+{
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber_GetClassID(%p)\n", This);
+    if (!pClassID) return E_POINTER;
+    
+    memcpy(pClassID,&CLSID_MPGrabber,16); //FIXME: stub
+    return E_FAIL;
+}
+
+/**
+ * \brief IMediaFilter::Stop (stops filter)
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ *
+ * \return S_OK success
+ * \return S_FALSE transition is not complete
+ *
+ * FIXME: fix return codes
+ */
+static long STDCALL DS_MPGrabber_Stop(IBaseFilter* This)
+{
+    HRESULT hr;
+    IMemAllocator* pAll;
+    DS_MPGrabber* this=(DS_MPGrabber*)This;
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber_Stop (%p)\n", This);
+
+    if (this->state==State_Stopped)
+        return S_OK;
+
+    if(this->state==State_Running){
+        if(this->mempinVideo){
+            hr=this->mempinVideo->vt->GetAllocator(this->mempinVideo,&pAll);
+            if(FAILED(hr) || !pAll){
+                Debug mp_msg(MSGT_TV,MSGL_WARN,"DS_MPGrabber_Stop (%p): video->GetAllocator failure!\n", This);
+                return E_FAIL;
+            }
+            hr=pAll->vt->Decommit(pAll);
+            if(FAILED(hr) || !pAll){
+                Debug mp_msg(MSGT_TV,MSGL_WARN,"DS_MPGrabber_Stop (%p): video->Decommit failure!\n", This);
+                pAll->vt->Release((IUnknown*)pAll);
+                return E_FAIL;
+            } 
+            pAll->vt->Release((IUnknown*)pAll);
+        }
+        if(this->mempinAudio){
+            hr=this->mempinAudio->vt->GetAllocator(this->mempinAudio,&pAll);
+            if(FAILED(hr) || !pAll){
+                Debug mp_msg(MSGT_TV,MSGL_WARN,"DS_MPGrabber_Stop (%p): audio->GetAllocator failure!\n", This);
+                return E_FAIL;
+            }
+            hr=pAll->vt->Decommit(pAll);
+            if(FAILED(hr) || !pAll){
+                Debug mp_msg(MSGT_TV,MSGL_WARN,"DS_MPGrabber_Stop (%p): audio->Decommit failure!\n", This);
+                pAll->vt->Release((IUnknown*)pAll);
+                return E_FAIL;
+            } 
+            pAll->vt->Release((IUnknown*)pAll);
+        }
+    }
+
+    this->state=State_Stopped;
+    return S_OK;
+}
+
+/**
+ * \brief IMediaFilter::Pause (pauses filter)
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ *
+ * \return S_OK success
+ * \return S_FALSE transition is not complete
+ * 
+ * \note
+ * When going into running state DirectShow first moves all filters into 
+ * paused state. Filter should prepare itself to start if it was in stopped
+ * state.
+ *
+ */
+static long STDCALL DS_MPGrabber_Pause(IBaseFilter* This)
+{
+    HRESULT hr;
+    IMemAllocator* pAll;
+    DS_MPGrabber* this=(DS_MPGrabber*)This;
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber_Pause(%p)\n", This);
+
+    if (this->state==State_Paused)
+        return S_OK;
+
+    if(this->state==State_Stopped){
+        if(this->mempinVideo){
+            hr=this->mempinVideo->vt->GetAllocator(this->mempinVideo,&pAll);
+            if(FAILED(hr) || !pAll){
+                Debug mp_msg(MSGT_TV,MSGL_WARN,"DS_MPGrabber_Pause (%p): video->GetAllocator failure!\n", This);
+                return E_FAIL;
+            }
+            hr=pAll->vt->Commit(pAll);
+            if(FAILED(hr) || !pAll){
+                Debug mp_msg(MSGT_TV,MSGL_WARN,"DS_MPGrabber_Pause (%p): video->Commit failure!\n", This);
+                pAll->vt->Release((IUnknown*)pAll);
+                return E_FAIL;
+            } 
+            pAll->vt->Release((IUnknown*)pAll);
+        }
+        if(this->mempinAudio){
+            hr=this->mempinAudio->vt->GetAllocator(this->mempinAudio,&pAll);
+            if(FAILED(hr) || !pAll){
+                Debug mp_msg(MSGT_TV,MSGL_WARN,"DS_MPGrabber_Pause (%p): audio->GetAllocator failure!\n", This);
+                return E_FAIL;
+            }
+            hr=pAll->vt->Commit(pAll);
+            if(FAILED(hr) || !pAll){
+                Debug mp_msg(MSGT_TV,MSGL_WARN,"DS_MPGrabber_Pause (%p): audio->Commit failure!\n", This);
+                pAll->vt->Release((IUnknown*)pAll);
+                return E_FAIL;
+            } 
+            pAll->vt->Release((IUnknown*)pAll);
+        }
+    }
+
+    this->state=State_Paused;
+    return S_OK;
+}
+
+/**
+ * \brief IMediaFilter::Run (starts filter)
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ * \param[in] tStart start time in 100 nanoseconds units
+ *
+ * \return S_OK success
+ * \return S_FALSE transition is not complete
+ * 
+ */
+static long STDCALL DS_MPGrabber_Run(IBaseFilter* This, REFERENCE_TIME tStart)
+{
+    HRESULT hr;
+    DS_MPGrabber* this=(DS_MPGrabber*)This;
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber_Run(%p)\n", This);
+    if (this->state==State_Stopped){
+        hr=This->vt->Pause(This);
+        if(FAILED(hr)) return hr;
+    }
+    this->m_tStart=tStart;
+    this->state=State_Running;
+    return S_OK;
+}
+
+/**
+ * \brief IMediaFilter::GetState (gets filter's current state)
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ * \param[in] dwMilliSecsTimeout -??
+ * \param[out] State address of variable that receives current state
+ *
+ * \return S_OK success
+ * \return E_POINTER Null pointer
+ * \return VFW_E_STATE_INTERMEDIATE Immediate state
+ * \return VFW_E_CANT_CUE Filter is active, but cannot deliver data
+ * 
+ */
+static long STDCALL DS_MPGrabber_GetState(IBaseFilter* This,
+					 /* [in] */ unsigned long dwMilliSecsTimeout,
+					  /* [out] */ FILTER_STATE *State)
+{
+    DS_MPGrabber* this=(DS_MPGrabber*)This;
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber_GetState(%p)\n", This);
+
+    if (!State) return E_POINTER;
+    *State=this->state;
+    return S_OK;
+}
+
+/**
+ * \brief IMediaFilter::SetSyncSource (notifies filter for used sync source in graph)
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ * \param[in] pClock pointer to IReferenceClock of used sync source
+ *
+ * \return S_OK success
+ * \return Apropriate return code otherwise
+ * 
+ */
+static long STDCALL DS_MPGrabber_SetSyncSource(IBaseFilter* This,
+					      /* [in] */ IReferenceClock *pClock)
+{
+    DS_MPGrabber* this=(DS_MPGrabber*)This;
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber_SetSyncSource(%p,%p)\n", This,pClock);
+    if(!pClock && !this->pClock) return S_OK;
+
+    if(this->pClock)
+        this->pClock->vt->Release((IUnknown*)this->pClock);
+
+    this->pClock=pClock;
+
+    if(this->pClock)
+	this->pClock->vt->AddRef((IUnknown*)this->pClock);
+    return S_OK;
+}
+
+/**
+ * \brief IMediaFilter::GetSyncSource (gets filter's sync source)
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ * \param[out] pClock address of variable that receives IReferenceClock of used sync source
+ *
+ * \return S_OK success
+ * \return E_POINTER Null pointer
+ * 
+ */
+static long STDCALL DS_MPGrabber_GetSyncSource(IBaseFilter* This,
+					      /* [out] */ IReferenceClock **pClock)
+{
+    DS_MPGrabber* this=(DS_MPGrabber*)This;
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber_GetSyncSource(%p)\n", This);
+
+    if(!pClock) return E_POINTER;
+    *pClock=this->pClock;
+    if(this->pClock)
+	this->pClock->vt->AddRef((IUnknown*)this->pClock);
+    return S_OK;
+}
+
+/**
+ * \brief IBaseFilter::EnumPins (returns pins enumerator)
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ * \param[out] ppEnum address of variable that receives IEnumPins interface
+ *
+ * \return S_OK success
+ * \return E_POINTER Null pointer
+ * \return E_OUTOFMEMORY Insufficient memory
+ * 
+ */
+static long STDCALL DS_MPGrabber_EnumPins(IBaseFilter* This,
+					 /* [out] */ IEnumPins **ppEnum)
+{
+    DS_MPGrabber* this=(DS_MPGrabber*)This;
+    Debug mp_msg(MSGT_TV,MSGL_DBG4,"DS_MPGrabber_EnumPins(%p) called\n", This);
+    if(!ppEnum) return E_POINTER;
+
+    if(this->pinVideo && this->pinAudio)
+        *ppEnum = (IEnumPins*) CEnumPinsCreate(this->pinVideo, this->pinAudio);
+    else if(this->pinVideo)
+        *ppEnum = (IEnumPins*) CEnumPinsCreate(this->pinVideo, NULL);
+    else if(this->pinAudio)
+        *ppEnum = (IEnumPins*) CEnumPinsCreate(this->pinAudio, NULL);
+    else
+        return E_POINTER;
+
+    return S_OK;
+}
+
+/**
+ * \brief IBaseFilter::FindPin (returns specified pin)
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ * \param[in] id id of pin to return
+ * \param[out] ppPin address of variable that receives IPin interface
+ *
+ * \return S_OK success
+ * \return E_POINTER Null pointer
+ * \return VFW_E_NOT_FOUND pin not found
+ * 
+ */
+static long STDCALL DS_MPGrabber_FindPin(IBaseFilter* This,
+					/* [string][in] */ const unsigned short* Id,
+					/* [out] */ IPin **ppPin)
+{
+    Debug unimplemented("DS_MPGrabber_FindPin\n", This);
+    return E_NOTIMPL;
+}
+
+/**
+ * \brief IBaseFilter::QueryFilterInfo (returns filter info)
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ * \param[out] pInfo pointer to FILTER_INFO that receives filter info
+ *
+ * \return S_OK success
+ * \return E_POINTER Null pointer
+ * 
+ */
+static long STDCALL DS_MPGrabber_QueryFilterInfo(IBaseFilter* This,
+						/* [out] */ FILTER_INFO *pInfo)
+{
+    DS_MPGrabber* this=(DS_MPGrabber*)This;
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber_QueryFilterInfo(%p) Returning:Graph=%p\n", This,((DS_MPGrabber*)This)->m_pGraph);
+
+    if (!pInfo) return E_POINTER;
+    memcpy(pInfo->achName,this->achName,128);
+    pInfo->pGraph=this->m_pGraph;
+    if(pInfo->pGraph)
+        pInfo->pGraph->vt->AddRef((IUnknown*)pInfo->pGraph);
+    return S_OK;
+}
+
+/**
+ * \brief IBaseFilter::JoinFilterGraph (notifies filter that it was added to filter graph)
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ * \param[in] pGraph pointer to IFilterGraph interface of parent graph
+ * \param[in] pName suggested name for the filter
+ *
+ * \return S_OK success
+ * \return E_POINTER Null pointer
+ * 
+ * \note
+ * pGraph==NULL means removing from graph
+ *
+ */
+static long STDCALL DS_MPGrabber_JoinFilterGraph(IBaseFilter* This,
+						/* [in] */ IFilterGraph* pGraph,
+						/* [string][in] */ WCHAR* pName)
+{
+    DS_MPGrabber* this=(DS_MPGrabber*)This;
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber_JoinFilterGraph(%p,%p,%s)\n", This,pGraph,(char*)pName);    
+
+    this->m_pGraph=pGraph;
+    if(pGraph && pName) wcscpy(this->achName,pName);
+    return S_OK;
+}
+
+/**
+ * \brief IBaseFilter::JoinFilterGraph (notifies filter that it was added to filter graph)
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ * \param[out] address variable that receives pointer to string, containing vendor info
+ *
+ * \return S_OK success
+ * \return E_POINTER Null pointer
+ * \return E_NOTIMPL Not implemented
+ * 
+ */
+static long STDCALL DS_MPGrabber_QueryVendorInfo(IBaseFilter* This,
+						/* [string][out] */ unsigned short** pVendorInfo)
+{
+    Debug unimplemented("DS_MPGrabber_QueryVendorInfo", This);
+    return E_NOTIMPL;
+}
+
+/**
+ * \brief DS_MPGrabber destructor
+ *
+ * \param[in] This pointer to IBaseFilter interface
+ * 
+ */
+void DS_MPGrabber_Destroy(DS_MPGrabber* This){
+    Debug mp_msg(MSGT_TV,MSGL_DBG4,"%s(%p) called\n","DS_MPGrabber_Destroy" , This);
+    if (This->mempinVideo)
+	This->mempinVideo->vt->Release((IUnknown*)This->mempinVideo);
+
+    if (This->pinVideo)
+	This->pinVideo->vt->Release((IUnknown*)This->pinVideo);
+
+    if (This->mempinAudio)
+	This->mempinAudio->vt->Release((IUnknown*)This->mempinAudio);
+
+    if (This->pinAudio)
+	This->pinAudio->vt->Release((IUnknown*)This->pinAudio);
+
+    if (This->m_pGraph)
+        This->m_pGraph->vt->Release((IUnknown*)This->m_pGraph);
+
+    if (This->pClock)
+        This->pClock->vt->Release((IUnknown*)This->pClock);
+
+    if (This->m_pFlags)
+        This->m_pFlags->vt->Release((IUnknown*)This->m_pFlags);
+
+    if (This->vt)
+	free(This->vt);
+    free(This);
+}
+
+
+/**
+ * \brief IUnknown::QueryInterface (queryes specified interface from filter)
+ *
+ * \param[in] This pointer to IUnknown interface
+ * \param[in] riid pointer to IID of interface to return
+ * \param[in] ppvObject address of variable that receives pointer to object
+ *
+ * \return S_OK success
+ * \return E_NOINTERFACE no specified interface
+ * \return E_POINTER Null pointer
+ *
+ */
+static long STDCALL DS_MPGrabber_QueryInterface(IUnknown * This, 
+					  const GUID* riid, void **ppvObject) 
+{ 
+    DS_MPGrabber* me = (DS_MPGrabber*)This;		
+    GUID* r; unsigned int i = 0;		
+    Debug mp_msg(MSGT_TV,MSGL_DBG4,"DS_MPGrabber_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)))	
+	{ 					
+	    me->vt->AddRef((IUnknown*)This); 	
+	    *ppvObject=This; 			
+	    return 0; 				
+	} 					
+    if(!memcmp(&IID_IAMFilterMiscFlags, riid, sizeof(IID_IAMFilterMiscFlags)))	
+    { 					
+        me->m_pFlags->vt->AddRef((IUnknown*)me->m_pFlags); 	
+        *ppvObject=me->m_pFlags;
+        return 0; 				
+    } 					
+    Debug mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber_QueryInterface failed! (GUID: %08x-%04x-%04x-%02x%02x-" 
+		 "%02x%02x%02x%02x%02x%02x\n", 
+		 riid->f1,  riid->f2,  riid->f3, 
+		 (unsigned char)riid->f4[0], (unsigned char)riid->f4[1], 
+		 (unsigned char)riid->f4[2], (unsigned char)riid->f4[3], 
+		 (unsigned char)riid->f4[4], (unsigned char)riid->f4[5], 
+		 (unsigned char)riid->f4[6], (unsigned char)riid->f4[7]); 
+
+    return E_NOINTERFACE;
+}
+						
+/**
+ * \brief IUnknown::AddRef (increases reference counter for interface)
+ *
+ * \param[in]  This pointer to IUnknown class
+ *
+ * \return new value of reference counter
+ *
+ */
+static long STDCALL DS_MPGrabber_AddRef(IUnknown * This) 
+{						
+    DS_MPGrabber* me=( DS_MPGrabber*)This;		
+    Debug mp_msg(MSGT_TV,MSGL_DBG4,"DS_MPGrabber_AddRef(%p) called (ref:%d)\n", This, me->refcount); 
+    return ++(me->refcount);
+}     						
+						
+/**
+ * \brief IUnknown::Release (desreases reference counter for interface)
+ *
+ * \param[in]  This pointer to IUnknown class
+ *
+ * \return S_OK - success
+ *
+ * \remarks
+ * When reference counter reaches zero calls destructor
+ *
+ */
+static long STDCALL DS_MPGrabber_Release(IUnknown * This) 
+{ 						
+    DS_MPGrabber* me=( DS_MPGrabber*)This;	 	
+    Debug mp_msg(MSGT_TV,MSGL_DBG4,"%s_Release(%p) called (new ref:%d)\n", "DS_MPGrabber",This, me->refcount - 1); 
+
+    if(--(me->refcount) == 0)
+		DS_MPGrabber_Destroy(me); 	
+    return S_OK;
+}
+
+/**
+ * \breaf DS_MPGrabber constructor
+ *
+ * \param video pointer to AM_MEDIA_TYPE for video pin
+ * \param audio pointer to AM_MEDIA_TYPE for audio pin
+ *
+ * \return pointer to DS_MPGrabber object if success
+ * \return NULL othewise
+ *
+ * \note
+ * if audio or video parameter is null corresponding pin will not be created
+ */
+DS_MPGrabber* DS_MPGrabberCreate(const AM_MEDIA_TYPE* video,const AM_MEDIA_TYPE* audio){
+    const char* em = NULL;
+    int init=0;
+    HRESULT result;
+    DS_MPGrabber* This;
+
+    mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabberCreate\n");
+
+    if(!audio && !video)
+        return NULL;
+    This = (DS_MPGrabber*) malloc(sizeof(DS_MPGrabber));
+    if (!This)
+	return NULL;
+
+    This->vt = (IBaseFilter_vt*) malloc(sizeof(IBaseFilter_vt));
+    if (!This->vt){
+        free(This);
+        return NULL;
+    }
+
+    This->pinVideo=NULL;
+    This->mempinVideo=NULL;
+
+    This->pinAudio=NULL;
+    This->mempinAudio=NULL;
+
+    This->m_pFlags=CAMFilterMiscFlagsCreate(1); //AM_FILTER_MISC_FLAGS_IS_RENDERER
+        if(!This->m_pFlags){
+        DS_MPGrabber_Destroy(This);
+        return NULL;
+    }
+    //video pin
+    if (video){
+        This->pinVideo = (IPin*) COutputPinCreate(video,This);
+        if (!This->pinVideo){
+            DS_MPGrabber_Destroy(This);
+            return NULL;
+        }
+
+        result=This->pinVideo->vt->QueryInterface((IUnknown*)This->pinVideo,&IID_IMemInputPin,(void**)&(This->mempinVideo));
+        if(FAILED(result) || !This->mempinVideo){
+            DS_MPGrabber_Destroy(This);
+            return NULL;
+        }
+    }
+
+    //audio pin
+    if(audio){
+        This->pinAudio = (IPin*) COutputPinCreate(audio,This);
+        if(!This->pinAudio){
+            DS_MPGrabber_Destroy(This);
+            return NULL;
+        }
+
+        result=This->pinAudio->vt->QueryInterface((IUnknown*)This->pinAudio,&IID_IMemInputPin,(void**)&(This->mempinAudio));
+        if(FAILED(result) || !This->mempinAudio){
+            DS_MPGrabber_Destroy(This);
+            return NULL;
+        }
+    }
+
+    This->refcount = 1;
+    This->m_pGraph=NULL;
+    This->pClock=NULL;
+    This->m_tStart=0;
+    This->state=State_Stopped;
+    memset(This->achName,0,128);
+
+    This->vt->QueryInterface = DS_MPGrabber_QueryInterface;
+    This->vt->AddRef = DS_MPGrabber_AddRef;
+    This->vt->Release = DS_MPGrabber_Release;
+    This->vt->GetClassID = DS_MPGrabber_GetClassID;
+    This->vt->Stop = DS_MPGrabber_Stop;
+    This->vt->Pause = DS_MPGrabber_Pause;
+    This->vt->Run = DS_MPGrabber_Run;
+    This->vt->GetState = DS_MPGrabber_GetState;
+    This->vt->SetSyncSource = DS_MPGrabber_SetSyncSource;
+    This->vt->GetSyncSource = DS_MPGrabber_GetSyncSource;
+    This->vt->EnumPins = DS_MPGrabber_EnumPins;
+    This->vt->FindPin = DS_MPGrabber_FindPin;
+    This->vt->QueryFilterInfo = DS_MPGrabber_QueryFilterInfo;
+    This->vt->JoinFilterGraph = DS_MPGrabber_JoinFilterGraph;
+    This->vt->QueryVendorInfo = DS_MPGrabber_QueryVendorInfo;
+
+    This->interfaces[0] = IID_IUnknown;
+    This->interfaces[1] = IID_IBaseFilter;
+    This->interfaces[2] = IID_IPersist;
+
+    This->FillBuffer=DS_Grabber_FillBuffer;
+    return This;
+
+}
Index: loader/dshow/DS_MPGrabber.h
===================================================================
--- loader/dshow/DS_MPGrabber.h	(revision 0)
+++ loader/dshow/DS_MPGrabber.h	(revision 0)
@@ -0,0 +1,50 @@
+#ifndef _DS_MPGRABBER_H_
+#define _DS_MPGRABBER_H_
+
+#include "outputpin.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+typedef struct _IAMFilterMiscFlags IAMFilterMiscFlags;
+typedef struct IAMFilterMiscFlags_vt {
+    INHERIT_IUNKNOWN();
+    HRESULT (*GetMiscFlags)(IAMFilterMiscFlags* This);
+} IAMFilterMiscFlags_vt;
+struct _IAMFilterMiscFlags {struct IAMFilterMiscFlags_vt* vt;};
+
+typedef struct _DS_MPGrabber DS_MPGrabber;
+struct _DS_MPGrabber
+{
+    IBaseFilter_vt *vt;
+    DECLARE_IUNKNOWN();
+
+    COutputPin* pinVideo;
+    IMemInputPin* mempinVideo;
+
+    COutputPin* pinAudio;
+    IMemInputPin* mempinAudio;
+
+    IFilterGraph* m_pGraph;
+    IReferenceClock* pClock;
+    IAMFilterMiscFlags* m_pFlags;
+    GUID interfaces[3];
+
+    FILTER_STATE state;
+    REFERENCE_TIME m_tStart;
+    WCHAR achName[128];
+    int STDCALL ( *FillBuffer)(DS_MPGrabber* This,char* buf,int len,int bVideo,long long* pPts);
+};
+
+
+DS_MPGrabber* DS_MPGrabberCreate(const AM_MEDIA_TYPE* video,const AM_MEDIA_TYPE* audio);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif //_DS_MPGRABBER_H_
+
+
Index: loader/dshow/guids.c
===================================================================
--- loader/dshow/guids.c	(revision 21934)
+++ loader/dshow/guids.c	(working copy)
@@ -1,5 +1,7 @@
 #include "guids.h"
 
+
+
 const GUID CLSID_DivxDecompressorCF={0x82CCd3E0, 0xF71A, 0x11D0,
     { 0x9f, 0xe5, 0x00, 0x60, 0x97, 0x78, 0xaa, 0xaa}};
 const GUID IID_IDivxFilterInterface={0xd132ee97, 0x3e38, 0x4030,
@@ -9,6 +11,8 @@
     {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
 const GUID IID_IBaseFilter={0x56a86895, 0x0ad4, 0x11ce,
     {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
+const GUID IID_IPin = {0x56a86891, 0x0ad4, 0x11ce, 
+    {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
 const GUID IID_IEnumPins={0x56a86892, 0x0ad4, 0x11ce,
     {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
 const GUID IID_IEnumMediaTypes={0x89c31040, 0x846b, 0x11ce,
Index: loader/dshow/guids.h
===================================================================
--- loader/dshow/guids.h	(revision 21934)
+++ loader/dshow/guids.h	(working copy)
@@ -44,6 +44,7 @@
 typedef GUID IID;
 
 extern const GUID IID_IBaseFilter;
+extern const GUID IID_IPin;
 extern const GUID IID_IEnumPins;
 extern const GUID IID_IEnumMediaTypes;
 extern const GUID IID_IMemInputPin;
@@ -82,4 +83,5 @@
 extern const GUID MEDIATYPE_Audio;
 extern const GUID MEDIASUBTYPE_PCM;
 
+
 #endif /* DS_GUIDS_H */
Index: loader/dshow/inputpin.c
===================================================================
--- loader/dshow/inputpin.c	(revision 21934)
+++ loader/dshow/inputpin.c	(working copy)
@@ -20,16 +20,6 @@
  * EnumPins
  ***********/
 
-typedef struct
-{
-    IEnumPins_vt* vt;
-    DECLARE_IUNKNOWN();
-    IPin* pin1;
-    IPin* pin2;
-    int counter;
-    GUID interfaces[2];
-} CEnumPins;
-
 static long STDCALL CEnumPins_Next(IEnumPins* This,
 				   /* [in] */ unsigned long cMediaTypes,
 				   /* [size_is][out] */ IPin** ppMediaTypes,
@@ -97,13 +87,17 @@
 
 static void CEnumPins_Destroy(CEnumPins* This)
 {
+    if(This->pin1)
+        This->pin1->vt->Release((IUnknown*)This->pin1);
+    if(This->pin2)
+        This->pin2->vt->Release((IUnknown*)This->pin2);
     free(This->vt);
     free(This);
 }
 
 IMPLEMENT_IUNKNOWN(CEnumPins)
 
-static CEnumPins* CEnumPinsCreate(IPin* p, IPin* pp)
+CEnumPins* CEnumPinsCreate(IPin* p, IPin* pp)
 {
     CEnumPins* This = (CEnumPins*) malloc(sizeof(CEnumPins));
 
@@ -113,6 +107,10 @@
     This->refcount = 1;
     This->pin1 = p;
     This->pin2 = pp;
+    if(p)
+        p->vt->AddRef((IUnknown*)p);
+    if(pp)
+        pp->vt->AddRef((IUnknown*)pp);
     This->counter = 0;
 
     This->vt = (IEnumPins_vt*) malloc(sizeof(IEnumPins_vt));
@@ -346,8 +344,7 @@
 
 static long STDCALL CBaseFilter_GetState(IBaseFilter* This,
 					 /* [in] */ unsigned long dwMilliSecsTimeout,
-					 // /* [out] */ FILTER_STATE *State)
-					 void* State)
+					 /* [out] */ FILTER_STATE *State)
 {
     Debug unimplemented("CBaseFilter_GetState", This);
     return E_NOTIMPL;
@@ -385,8 +382,7 @@
 }
 
 static long STDCALL CBaseFilter_QueryFilterInfo(IBaseFilter* This,
-						// /* [out] */ FILTER_INFO *pInfo)
-						void* pInfo)
+						/* [out] */ FILTER_INFO *pInfo)
 {
     Debug unimplemented("CBaseFilter_QueryFilterInfo", This);
     return E_NOTIMPL;
@@ -507,8 +503,7 @@
 
 static long STDCALL CBaseFilter2_GetState(IBaseFilter* This,
 					  /* [in] */ unsigned long dwMilliSecsTimeout,
-					  // /* [out] */ FILTER_STATE *State)
-					  void* State)
+					  /* [out] */ FILTER_STATE *State)
 {
     Debug unimplemented("CBaseFilter2_GetState", This);
     return E_NOTIMPL;
@@ -545,8 +540,7 @@
 }
 
 static long STDCALL CBaseFilter2_QueryFilterInfo(IBaseFilter* This,
-						 // /* [out] */ FILTER_INFO *pInfo)
-						 void* pInfo)
+						 /* [out] */ FILTER_INFO *pInfo)
 {
     Debug unimplemented("CBaseFilter2_QueryFilterInfo", This);
     return E_NOTIMPL;
Index: loader/dshow/inputpin.h
===================================================================
--- loader/dshow/inputpin.h	(revision 21934)
+++ loader/dshow/inputpin.h	(working copy)
@@ -67,4 +67,16 @@
 
 CRemotePin2* CRemotePin2Create(CBaseFilter2* parent);
 
+typedef struct
+{
+    IEnumPins_vt* vt;
+    DECLARE_IUNKNOWN();
+    IPin* pin1;
+    IPin* pin2;
+    int counter;
+    GUID interfaces[2];
+} CEnumPins;
+
+CEnumPins* CEnumPinsCreate(IPin* p, IPin* pp);
+
 #endif /* DS_INPUTPIN_H */
Index: loader/dshow/interfaces.h
===================================================================
--- loader/dshow/interfaces.h	(revision 21934)
+++ loader/dshow/interfaces.h	(working copy)
@@ -16,6 +16,7 @@
 typedef struct _IFilterGraph IFilterGraph;
 
 typedef struct _IBaseFilter IBaseFilter;
+typedef struct _IEnumFilters IEnumFilters;
 
 typedef enum
 {
@@ -38,6 +39,17 @@
     long cbPrefix;
 } ALLOCATOR_PROPERTIES;
 
+typedef enum _FilterState {
+    State_Stopped = 0,
+    State_Paused = 1,
+    State_Running = 2
+} FILTER_STATE;
+
+typedef struct _FilterInfo {
+    WCHAR achName[128];
+    IFilterGraph *pGraph;
+} FILTER_INFO;
+
 typedef struct _IEnumMediaTypes IEnumMediaTypes;
 typedef struct IEnumMediaTypes_vt
 {
@@ -191,8 +203,7 @@
 			     REFERENCE_TIME tStart);
     HRESULT STDCALL ( *GetState )(IBaseFilter * This,
 				  /* [in] */ unsigned long dwMilliSecsTimeout,
-				  ///* [out] */ FILTER_STATE *State);
-				  void* State);
+				  /* [out] */ FILTER_STATE *State);
     HRESULT STDCALL ( *SetSyncSource )(IBaseFilter* This,
 				       /* [in] */ IReferenceClock *pClock);
     HRESULT STDCALL ( *GetSyncSource )(IBaseFilter* This,
@@ -203,8 +214,7 @@
 				 /* [string][in] */ const unsigned short* Id,
 				 /* [out] */ IPin** ppPin);
     HRESULT STDCALL ( *QueryFilterInfo )(IBaseFilter* This,
-					 // /* [out] */ FILTER_INFO *pInfo);
-					 void* pInfo);
+					 /* [out] */ FILTER_INFO *pInfo);
     HRESULT STDCALL ( *JoinFilterGraph )(IBaseFilter* This,
 					 /* [in] */ IFilterGraph* pGraph,
 					 /* [string][in] */ const unsigned short* pName);
@@ -329,4 +339,34 @@
     HRESULT STDCALL ( *get_AspectRatio )(IDivxFilterInterface* This, int* x, IDivxFilterInterface* Thisit, int* y);
 };
 
+typedef struct IFilterGraph_vt 
+{
+    INHERIT_IUNKNOWN();
+
+    HRESULT STDCALL (*AddFilter)(IFilterGraph* This,IBaseFilter* pFilter,LPCWSTR pName);
+    HRESULT STDCALL (*RemoveFilter)(IFilterGraph* This,IBaseFilter* pFilter);
+    HRESULT STDCALL (*EnumFilters)(IFilterGraph* This,IEnumFilters** ppEnum);
+    HRESULT STDCALL (*FindFilterByName)(IFilterGraph* This,LPCWSTR pName,IBaseFilter** ppFilter);
+    HRESULT STDCALL (*ConnectDirect)(IFilterGraph* This,IPin* ppinOut,IPin* ppinIn,const AM_MEDIA_TYPE* pmt);
+    HRESULT STDCALL (*Reconnect)(IFilterGraph* This,IPin* ppin);
+    HRESULT STDCALL (*Disconnect)(IFilterGraph* This,IPin* ppin);
+    HRESULT STDCALL (*SetDefaultSyncSource)(IFilterGraph* This);
+} IFilterGraph_vt;
+struct _IFilterGraph {struct IFilterGraph_vt* vt;};
+
+typedef DWORD_PTR HSEMAPHORE;
+typedef DWORD_PTR HEVENT;
+
+typedef struct IReferenceClock_vt {
+    INHERIT_IUNKNOWN();
+
+    HRESULT STDCALL ( *GetTime)(IReferenceClock* This,REFERENCE_TIME* pTime);
+    HRESULT STDCALL ( *AdviseTime)(IReferenceClock* This,REFERENCE_TIME baseTime,REFERENCE_TIME streamTime,HEVENT hEvent,DWORD_PTR* pdwAdviseCookie);
+    HRESULT STDCALL ( *AdvisePeriodic)(IReferenceClock* This,REFERENCE_TIME startTime,REFERENCE_TIME periodTime,HSEMAPHORE hSemaphore,DWORD_PTR* pdwAdviseCookie);
+    HRESULT STDCALL ( *Unadvise)(IReferenceClock* This,DWORD_PTR dwAdviseCookie);
+} IReferenceClock_vt;
+struct _IReferenceClock {struct IReferenceClock_vt* vt;};
+
+
+
 #endif  /* DS_INTERFACES_H */
Index: loader/dshow/outputpin.c
===================================================================
--- loader/dshow/outputpin.c	(revision 21934)
+++ loader/dshow/outputpin.c	(working copy)
@@ -11,41 +11,326 @@
 #include <string.h>
 #include <stdlib.h>
 
-/*
-    An object beyond interface IEnumMediaTypes.
-    Returned by COutputPin through call IPin::EnumMediaTypes().
-*/
 
+
+#ifndef NOAVIFILE_HEADERS
+#include "audiodecoder.h"
+#include "except.h"
+#else
+#include "libwin32.h"
+#endif
+
+#define VFW_E_NOT_CONNECTED 		 ((HRESULT)0x80040209L)
+#define VFW_E_TYPE_NOT_ACCEPTED          ((HRESULT)0x8004022AL)
+
+
+#include "DS_Filter.h"
+
+#define Debug if(0)
+
+// FIXME: I don't sure that it is proper place for AM_MEDIA_TYPE related routines
+
+/**
+ * \brief print info from AM_MEDIA_TYPE structure
+ * \param[in] pmt pointer to AM_MEDIA_TYPE
+ * 
+ * routine used for debug purposes
+ *
+ */
+void print_pmt_info(const AM_MEDIA_TYPE* pmt){
+    WAVEFORMATEX* pWF;
+    VIDEOINFOHEADER* Vhdr;
+    int i;
+    GUID* iid;
+    
+   
+    printf("=======================\n");
+    printf("AM_MEDIA_TYPE:\n");
+    printf("-(Ptr:%p)--------\n",pmt);
+    for(i=0;i<sizeof(AM_MEDIA_TYPE);i++){
+        printf("%02x ",(BYTE)((BYTE*)pmt)[i]);
+        if((i+1)%8==0) printf("\n");
+    }
+    if((i)%8!=0) printf("\n");
+    printf("-(Ptr:%p)--(%02d)--\n",pmt->pbFormat,pmt->cbFormat);
+    for(i=0;i<pmt->cbFormat;i++){
+        printf("%02x ",(BYTE)pmt->pbFormat[i]);
+        if((i+1)%8==0) printf("\n");
+    }
+    if((i)%8!=0) printf("\n");
+    printf("-----------------------\n");
+    iid=&(pmt->subtype);
+    printf("Subtype:     %08x-%04x-%04x-%02x%02x-"
+		 "%02x%02x%02x%02x%02x%02x\n",
+		 iid->f1,  iid->f2,  iid->f3,
+		 (unsigned char)iid->f4[1], (unsigned char)iid->f4[0],
+		 (unsigned char)iid->f4[2], (unsigned char)iid->f4[3],
+		 (unsigned char)iid->f4[4], (unsigned char)iid->f4[5],
+		 (unsigned char)iid->f4[6], (unsigned char)iid->f4[7]);
+
+    iid=&(pmt->formattype);
+    printf("Format type: %08x-%04x-%04x-%02x%02x-"
+		 "%02x%02x%02x%02x%02x%02x\n",
+		 iid->f1,  iid->f2,  iid->f3,
+		 (unsigned char)iid->f4[1], (unsigned char)iid->f4[0],
+		 (unsigned char)iid->f4[2], (unsigned char)iid->f4[3],
+		 (unsigned char)iid->f4[4], (unsigned char)iid->f4[5],
+		 (unsigned char)iid->f4[6], (unsigned char)iid->f4[7]);
+    if(pmt && memcmp(&pmt->formattype,&FORMAT_WaveFormatEx,16)==0 && pmt->pbFormat){
+    pWF=(WAVEFORMATEX*)pmt->pbFormat;
+    printf("PMT: nChannels %d\n",pWF->nChannels);
+    printf("PMT: nSamplesPerSec %d\n",pWF->nSamplesPerSec);
+    printf("PMT: wBitsPerSample %d\n",pWF->wBitsPerSample);
+    printf("PMT: nBlockAlign %d\n",pWF->nBlockAlign);
+    printf("PMT: nAvgBytesPerSec %d\n",pWF->nAvgBytesPerSec);
+    printf("PMT: SampleSize %ld\n",pmt->lSampleSize);
+    }
+    if(pmt && memcmp(&pmt->formattype,&FORMAT_VideoInfo,16)==0 && pmt->pbFormat){
+    Vhdr=(VIDEOINFOHEADER*)pmt->pbFormat;
+    printf("Vhdr: dwBitRate %ld\n",Vhdr->dwBitRate);
+    printf("Vhdr: biWidth %ld\n",Vhdr->bmiHeader.biWidth);
+    printf("Vhdr: biHeight %d\n",Vhdr->bmiHeader.biHeight);
+    printf("Vhdr: biBitCount %d\n",Vhdr->bmiHeader.biBitCount);
+    if(Vhdr->bmiHeader.biCompression){
+        printf("Vhdr: biComression 0x%08x (%s)\n",Vhdr->bmiHeader.biCompression,vo_format_name(Vhdr->bmiHeader.biCompression));
+    }else
+        printf("Vhdr: biComression 0x00000000\n");
+
+    }
+    printf("=======================\n");
+}
+
+/**
+ * \brief frees memory, pointed by pbFormat and pUnk members of AM_MEDIA_TYPE structure
+ *
+ * \param[in] pmt pointer to structure
+ *
+ * \note
+ * routine does not frees memory allocated for AM_MEDIA_TYPE, so given pointer will be
+ * valid after this routine call.
+ *
+ */
+void free_media_type(AM_MEDIA_TYPE* pmt){
+    if(!pmt) return;
+    if (pmt->cbFormat){
+        CoTaskMemFree(pmt->pbFormat);
+        pmt->pbFormat=NULL;
+        pmt->cbFormat=0;
+    }
+    if (pmt->pUnk){
+        pmt->pUnk->vt->Release(pmt->pUnk);
+        pmt->pUnk=NULL;
+    }
+}
+
+/**
+ * \brief frees memory allocated for AM_MEDIA_TYPE structure, including pbFormat and pUnk
+ *        members
+ *
+ * \param[in] pmt pointer to structure
+ *
+ * \note
+ * after call to this routine, pointer to AM_MEDIA_TYPE will not be valid anymore
+ *
+ */
+void delete_media_type(AM_MEDIA_TYPE* pmt){
+    if(!pmt) return;
+    free_media_type(pmt);
+    CoTaskMemFree(pmt);
+}
+
+/**
+ * \brief copyies info from source to destination AM_MEDIA_TYPE structures
+ *
+ * \param[in] pSrc pointer to AM_MEDIA_TYPE structure to copy data from
+ * \param[out] pDst pointer to AM_MEDIA_TYPE structure to copy data to
+ *
+ * \return S_OK - success
+ * \return E_POINTER - pSrc or pDst is NULL or (pSrc->cbFormat && !pSrc->pbFormat)
+ * \return E_INVALIDARG - (pSrc == pDst) 
+ * \return E_OUTOFMEMORY - Insufficient memory
+ *
+ * \note
+ * - pDst must point to existing AM_MEDIA_TYPE structure (all data will be overwritten)
+ * - if pDst->pbFormat!=NULL this will cause memory leak (as described in Directshow SDK)!
+ *
+ */
+HRESULT copy_media_type(AM_MEDIA_TYPE* pDst,const AM_MEDIA_TYPE* pSrc){
+    Debug printf("%s(%p) called\n", "copy_media_type",pSrc);
+
+    if(!pSrc || !pDst) return E_POINTER;
+
+    if(pSrc == pDst) return E_INVALIDARG;
+
+    if(!pSrc->pbFormat && pSrc->cbFormat) return E_POINTER;
+    
+    *pDst=*pSrc;
+
+    if(pDst->cbFormat>0){
+        pDst->pbFormat=CoTaskMemAlloc(pDst->cbFormat);
+        if(!pDst->pbFormat){
+            pDst->pbFormat=NULL;
+            pDst->cbFormat=0;
+            return E_OUTOFMEMORY;
+        }else
+          memcpy(pDst->pbFormat,pSrc->pbFormat,pDst->cbFormat);
+    }
+#if 0
+    //for debug purpose
+    printf ("================CopyMEdiaTyoe: Source===========\n");
+    print_pmt_info(pSrc);
+    printf ("================CopyMEdiaTyoe: Dest===========\n");
+    print_pmt_info(pDst);
+#endif
+    return S_OK;
+}
+
+/**
+ * \brief allocates new AM_MEDIA_TYPE structure and fills it with info from given one
+ *
+ * \param[in] pSrc pointer to AM_MEDIA_TYPE structure to copy data from
+ *
+ * \return result code, returned from copy_media_type
+ *
+ */
+AM_MEDIA_TYPE* create_media_type(const AM_MEDIA_TYPE* pSrc){
+    HRESULT hr;
+    AM_MEDIA_TYPE* pDst=CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));    
+    if (!pDst) return NULL;   
+    hr=copy_media_type(pDst,pSrc);
+    if(!FAILED(hr)) return pDst;
+    //Copy failed
+    CoTaskMemFree(pDst);
+    return NULL;
+}
+
 static inline int output_unimplemented(const char* s, void* p)
 {
     Debug printf("%s(%p) called (UNIMPLEMENTED)", s, p);
     return E_NOTIMPL;
 }
 
+/**
+    An object beyond interface IEnumMediaTypes.
+    Returned by COutputPin through call IPin::EnumMediaTypes().
+*/
 typedef struct CEnumMediaTypes
 {
     IEnumMediaTypes_vt* vt;
     DECLARE_IUNKNOWN();
     AM_MEDIA_TYPE type;
     GUID interfaces[2];
+    int counter;
 } CEnumMediaTypes;
 
+/**
+   IMemOutput interface implementation
+*/
 struct _COutputMemPin
 {
     IMemInputPin_vt* vt;
     DECLARE_IUNKNOWN();
     char** frame_pointer;
     long* frame_size_pointer;
-    MemAllocator* pAllocator;
+    /*
+     FIXME:
+     Previous version uses MemAllocator pointer. For calling from DS_Filter or DS_*Decoder
+     this does not matter, because pAllocator can contain only MemAllocator object.
+     But when using inside DirectShow graph this pointer would contain pointer to 
+     IMemAllocator interface, provided by DirectShow graph.
+    */
+    IMemAllocator* pAllocator;
     COutputPin* parent;
+
+#if defined(HAVE_TV_DSHOW)
+    CRITICAL_SECTION crit;
+    char** ringbuffer;
+    long long* pts;
+    long long* sampleno;
+   
+    int buffersize;
+    int blocksize;
+    int head;
+    int tail;
+    int count;
+#endif
 };
 
+#if defined(HAVE_TV_DSHOW)
+/**
+ * \brief free COutputMemPin's internal ringbuffer
+ *
+ * \param[in] this pointer to COutputPin object
+ * 
+ */
+void free_ringbuffer(COutputMemPin* this){
+    int i;
+    Debug printf("free_ringbuffer(%p) called\n", this);
+    if(!this->ringbuffer) return;
+
+    for(i=0;i<this->buffersize;i++) free(this->ringbuffer[i]);
+    free(this->ringbuffer);
+    if (this->pts) free(this->pts);
+    if (this->sampleno) free(this->sampleno);
+    
+    this->ringbuffer=NULL;
+    this->sampleno=NULL;
+    this->pts=NULL;
+
+    this->head=0;
+    this->tail=0;
+    this->count=0;
+    DeleteCriticalSection(&(this->crit));
+}
+
+/**
+ * \brief initialize COutputMemPin's internal buffer
+ *
+ * \param[in] this COutputMemPin object
+ * \param[in] ringbuffer size in blocks
+ * \param[in] blocksize in bytes
+ *
+ * \return currently only 1
+ *
+ */
+int init_ringbuffer(COutputMemPin*this,int buffersize,int blocksize){
+    int i;
+    Debug printf("init_ringbuffer(%p) called\n", this);
+    if(this->ringbuffer) free_ringbuffer(this);
+
+    this->buffersize=buffersize<50?50:buffersize; 
+    this->blocksize=blocksize;
+
+    this->ringbuffer=(char**)malloc(this->buffersize*sizeof(char*));
+    for (i=0;i<this->buffersize;i++) this->ringbuffer[i]=(char*)malloc(this->blocksize*sizeof(char));
+    this->pts=(long long*)malloc(this->buffersize*sizeof(long long));
+    this->sampleno=(long long*)malloc(this->buffersize*sizeof(long long));
+    this->head=0;
+    this->tail=0;
+    this->count=0;
+    InitializeCriticalSection(&(this->crit));
+    return 1;
+}
+#endif
+
+/**
+ * \brief IEnumMediaTypes:Next (skips over a specified number of media types)
+ *
+ * \param[in]  This pointer to CEnumMEdiaTypes object
+ * \param[in]  cMediaTypes number of media types to skip
+ *
+ * \return S_OK - success
+ * \return S_FALSE - success
+ * \return VFW_E_ENUM_OUT_OF_SYNC - pin's state has changed and is now inconsistent with enumerator
+ *
+ */
 static HRESULT STDCALL CEnumMediaTypes_Next(IEnumMediaTypes * This,
 					    /* [in] */ ULONG cMediaTypes,
 					    /* [size_is][out] */ AM_MEDIA_TYPE **ppMediaTypes,
 					    /* [out] */ ULONG *pcFetched)
 {
-    AM_MEDIA_TYPE* type = &((CEnumMediaTypes*)This)->type;
+    CEnumMediaTypes* this=(CEnumMediaTypes*)This;
+
     Debug printf("CEnumMediaTypes::Next(%p) called\n", This);
     if (!ppMediaTypes)
 	return E_INVALIDARG;
@@ -54,34 +339,70 @@
     if (cMediaTypes <= 0)
 	return 0;
 
+    if(this->counter==1){
+        if (pcFetched)
+            *pcFetched=0;
+        return S_FALSE;
+    }
     if (pcFetched)
 	*pcFetched=1;
-    ppMediaTypes[0] = malloc(sizeof(AM_MEDIA_TYPE));
-    // copy structures - C can handle this...
-    **ppMediaTypes = *type;
-    if (ppMediaTypes[0]->pbFormat)
-    {
-	ppMediaTypes[0]->pbFormat=malloc(ppMediaTypes[0]->cbFormat);
-	memcpy(ppMediaTypes[0]->pbFormat, type->pbFormat, ppMediaTypes[0]->cbFormat);
-    }
+    ppMediaTypes[0] = create_media_type(&(this->type));
+    if(!ppMediaTypes[0]) return E_OUTOFMEMORY;
+
+    this->counter++;
+
     if (cMediaTypes == 1)
 	return 0;
     return 1;
 }
 
 /* I expect that these methods are unused. */
+
+/**
+ * \brief IEnumMediaTypes::Reset (skips over a specified number of media types)
+ *
+ * \param[in]  This pointer to CEnumMEdiaTypes object
+ * \param[in]  cMediaTypes number of media types to skip
+ *
+ * \return S_OK - success
+ * \return S_FALSE - success
+ * \return VFW_E_ENUM_OUT_OF_SYNC - pin's state has changed and is now inconsistent with enumerator
+ *
+ */
 static HRESULT STDCALL CEnumMediaTypes_Skip(IEnumMediaTypes * This,
 					    /* [in] */ ULONG cMediaTypes)
 {
     return output_unimplemented("CEnumMediaTypes::Skip", This);
 }
 
+/**
+ * \brief IEnumMediaTypes::Reset (resets enumeration sequence to beginning)
+ *
+ * \param[in]  This pointer to CEnumMEdiaTypes object
+ *
+ * \return S_OK - success
+ *
+ */
 static HRESULT STDCALL CEnumMediaTypes_Reset(IEnumMediaTypes * This)
 {
     Debug printf("CEnumMediaTypes::Reset(%p) called\n", This);
+    ((CEnumMediaTypes*)This)->counter = 0;
     return 0;
 }
 
+/**
+ * \brief IEnumMediaTypes::Clone (makes a copy of enumerator, returned object
+ *        starts at the same position as original)
+ *
+ * \param[in]  This pointer to CEnumMEdiaTypes object
+ * \param[out] ppEnum address of variable that receives pointer to IEnumMediaTypes interface
+ *
+ * \return S_OK - success
+ * \return E_OUTOFMEMRY - Insufficient memory
+ * \return E_POINTER - Null pointer
+ * \return VFW_E_ENUM_OUT_OF_SYNC - pin's state has changed and is now inconsistent with enumerator
+ *
+ */
 static HRESULT STDCALL CEnumMediaTypes_Clone(IEnumMediaTypes * This,
 				      /* [out] */ IEnumMediaTypes **ppEnum)
 {
@@ -89,13 +410,20 @@
     return E_NOTIMPL;
 }
 
+/**
+ * \brief CEnumMediaTypes destructor
+ *
+ * \param[in]  This pointer to CEnumMediaTypes object
+ *
+ */
 static void CEnumMediaTypes_Destroy(CEnumMediaTypes* This)
 {
+    free_media_type(&(This->type));
     free(This->vt);
     free(This);
 }
 
-// IPin->IUnknown methods
+// IEnumMediaTypes->IUnknown methods
 IMPLEMENT_IUNKNOWN(CEnumMediaTypes)
 
 static CEnumMediaTypes* CEnumMediaTypesCreate(const AM_MEDIA_TYPE* amt)
@@ -113,7 +441,7 @@
     }
 
     This->refcount = 1;
-    This->type = *amt;
+    copy_media_type(&(This->type),amt);
 
     This->vt->QueryInterface = CEnumMediaTypes_QueryInterface;
     This->vt->AddRef = CEnumMediaTypes_AddRef;
@@ -132,9 +460,27 @@
 
 /*************
  * COutputPin
+ *
+ * \warning
+ * This is implementation of INPUT pin in DirectShow's terms
+ *
  *************/
 
 
+/**
+ *
+ * \brief IUnknown::QueryInterface (query object for interface)
+ * \param[in]  This pointer to IUnknown interface
+ * \param[in]  iid  GUID of requested interface
+ * \param[out] ppv  receives pointer to interface
+ *
+ * \return S_OK - success (and *ppv contains valid pointer)
+ * \return E_NOINTERFACE - interface not found (and *ppv was set NULL)
+ *
+ * \note
+ * Make sure to call Release on received interface when you are done
+ *
+ */
 static HRESULT STDCALL COutputPin_QueryInterface(IUnknown* This, const GUID* iid, void** ppv)
 {
     COutputPin* p = (COutputPin*) This;
@@ -149,6 +495,12 @@
 	p->vt->AddRef(This);
         return 0;
     }
+    if (memcmp(iid, &IID_IPin, 16) == 0)
+    {
+	*ppv = p;
+	p->vt->AddRef(This);
+       return 0;
+    }
     if (memcmp(iid, &IID_IMemInputPin, 16) == 0)
     {
 	*ppv = p->mempin;
@@ -167,11 +519,26 @@
 }
 
 // IPin methods
+
+/**
+ * \brief IPin::Connect (connects pin to another pin)
+ *
+ * \param[in] This          pointer to IPin interface
+ * \param[in] pReceivePin   pointer to IPin interface of remote pin
+ * \param[in] pmt suggested media type for link. Can be NULL (any media type)
+ *
+ * \return S_OK - success.
+ * \return VFW_E_ALREADY_CONNECTED - pin already connected
+ * \return VFW_E_NOT_STOPPED - filter is active
+ * \return VFW_E_TYPE_NOT_ACCEPT - type is not acceptable
+ * \return Apropriate error code otherwise.
+ *
+ */
 static HRESULT STDCALL COutputPin_Connect(IPin * This,
 				    /* [in] */ IPin *pReceivePin,
 				    /* [in] */ /* const */ AM_MEDIA_TYPE *pmt)
 {
-    Debug printf("COutputPin_Connect() called\n");
+    Debug printf("COutputPin_Connect(%p) called\n",This);
 /*
     *pmt=((COutputPin*)This)->type;
     if(pmt->cbFormat>0)
@@ -185,21 +552,81 @@
     // if I put return 0; here, it crashes
 }
 
+/**
+ * \brief IPin::ReceiveConnection (accepts a connection from another pin)
+ *
+ * \param[in] This       pointer to IPin interface
+ * \param[in] pConnector connecting pin's IPin interface
+ * \param[in] pmt        suggested media type for connection
+ *
+ * \return S_OK - success
+ * \return E_POINTER - Null pointer
+ * \return VFW_E_ALREADY_CONNECTED - pin already connected
+ * \return VFW_E_NOT_STOPPED - filter is active
+ * \return VFW_E_TYPE_NOT_ACCEPT - type is not acceptable
+ *
+ * \note
+ * When returning S_OK method should also do the following:
+ *  - store media type and return the same type in IPin::ConnectionMediaType
+ *  - store pConnector and return it in IPin::ConnectedTo
+ *
+ */
 static HRESULT STDCALL COutputPin_ReceiveConnection(IPin * This,
 						    /* [in] */ IPin *pConnector,
 						    /* [in] */ const AM_MEDIA_TYPE *pmt)
 {
+    COutputPin* this=(COutputPin*)This;
     Debug printf("COutputPin_ReceiveConnection(%p) called\n", This);
-    ((COutputPin*)This)->remote = pConnector;
+    Debug printf("Suggested format:\n");
+    Debug print_pmt_info(pmt);
+    if(This->vt->QueryAccept(This,pmt)!=S_OK){
+    	Debug printf("ReceiveConnection: Rejecting format.\n");
+        return VFW_E_TYPE_NOT_ACCEPTED;
+    }else
+    	Debug printf("ReceiveConnection: Accepting format.\n");
+    this->remote = pConnector;
+    pConnector->vt->AddRef((IUnknown*)pConnector);
+    free_media_type(&(this->type));
+    copy_media_type(&(this->type),pmt);
     return 0;
 }
 
+/**
+ * \brief IPin::Disconnect (accepts a connection from another pin)
+ *
+ * \param[in] This pointer to IPin interface
+ *
+ * \return S_OK - success
+ * \return S_FALSE - pin was not connected
+ * \return VFW_E_NOT_STOPPED - filter is active
+ *
+ * \note
+ *   To break connection you have to also call Disconnect on other pin
+ */
 static HRESULT STDCALL COutputPin_Disconnect(IPin * This)
 {
+    COutputPin* this=(COutputPin*)This;
     Debug printf("COutputPin_Disconnect(%p) called\n", This);
-    return 1;
+    if(this->remote){
+        this->remote->vt->Release((IUnknown*)this->remote);
+        this->remote=NULL;
+    }
+    return S_OK;
 }
 
+/**
+ * \brief IPin::ConnectedTo (retrieves pointer to the connected pin, if such exist)
+ *
+ * \param[in]  This pointer to IPin interface
+ * \param[out] pPin pointer to remote pin's IPin interface
+ *
+ * \return S_OK - success
+ * \return E_POINTER - Null pointer
+ * \return VFW_E_NOT_CONNECTED - pin is not connected
+ *
+ * \note
+ * Caller must call Release on received IPin, when done
+ */
 static HRESULT STDCALL COutputPin_ConnectedTo(IPin * This,
 					/* [out] */ IPin **pPin)
 {
@@ -207,30 +634,69 @@
     if (!pPin)
 	return E_INVALIDARG;
     *pPin = ((COutputPin*)This)->remote;
+    if (!*pPin)
+        return VFW_E_NOT_CONNECTED;
+    (*pPin)->vt->AddRef((IUnknown*)*pPin);
+
     return 0;
 }
 
+/**
+ * \brief IPin::ConnectionMediaType (retrieves media type for connection, if such exist)
+ *
+ * \param[in]  This pointer to IPin interface
+ * \param[out] pmt pointer to AM_MEDIA_TYPE,  that receives connection media type
+ *
+ * \return S_OK - success
+ * \return E_POINTER - Null pointer
+ * \return VFW_E_NOT_CONNECTED - pin is not connected
+ *
+ */
 static HRESULT STDCALL COutputPin_ConnectionMediaType(IPin * This,
 						      /* [out] */ AM_MEDIA_TYPE *pmt)
 {
-    Debug printf("CInputPin::ConnectionMediaType() called\n");
+    Debug printf("COutputPin_ConnectionMediaType(%p) called\n",This);
     if (!pmt)
 	return E_INVALIDARG;
-    *pmt = ((COutputPin*)This)->type;
-    if (pmt->cbFormat>0)
-    {
-	pmt->pbFormat=malloc(pmt->cbFormat);
-	memcpy(pmt->pbFormat, ((COutputPin*)This)->type.pbFormat, pmt->cbFormat);
-    }
-    return 0;
+    return copy_media_type(pmt,(&((COutputPin*)This)->type));
 }
 
+/**
+ * \brief IPin::QueryPinInfo (retrieves information about the pin)
+ *
+ * \param[in]  This  pointer to IPin interface
+ * \param[out] pInfo pointer to PIN_INFO structure, that receives pin info
+ *
+ * \return S_OK - success
+ * \return E_POINTER - Null pointer
+ *
+ * \note
+ * If pInfo->pFilter is not NULL, then caller must call Release on pInfo->pFilter when done
+ *
+ */
 static HRESULT STDCALL COutputPin_QueryPinInfo(IPin * This,
 					       /* [out] */ PIN_INFO *pInfo)
 {
-    return output_unimplemented("COutputPin_QueryPinInfo", This);
+    Debug printf("COutputPin_QueryPinInfo(%p) called\n", This);
+    if(!pInfo)
+        return E_INVALIDARG;
+    pInfo->pFilter=((COutputPin*)This)->pFilter;
+    pInfo->pFilter->vt->AddRef((IUnknown*)pInfo->pFilter);
+    pInfo->dir=PINDIR_INPUT;
+    memset(pInfo->achName,0,128); //FIXME need some name
+    return 0;
 }
 
+/**
+ * \brief IPin::QueryDirection (retrieves pin direction)
+ *
+ * \param[in]  This    pointer to IPin interface
+ * \param[out] pPinDir pointer to variable, that receives pin direction (PINDIR_INPUT,PINDIR_OUTPUT)
+ *
+ * \return S_OK - success
+ * \return E_POINTER - Null pointer
+ *
+ */
 static HRESULT STDCALL COutputPin_QueryDirection(IPin * This,
 					   /* [out] */ PIN_DIRECTION *pPinDir)
 {
@@ -241,28 +707,104 @@
     return 0;
 }
 
+/**
+ * \brief IPin::QueryId (retrieves pin identificator)
+ *
+ * \param[in]  This pointer to IPin interface
+ * \param[out] Id   adress of variable, that receives string with pin's Id.
+ *
+ * \return S_OK - success
+ * \return E_OUTOFMEMORY - Insufficient memory
+ * \return E_POINTER     - Null pointer
+ *
+ * \note
+ * Pin's Id is not the same as pin's name
+ *
+ */
 static HRESULT STDCALL COutputPin_QueryId(IPin * This,
 					  /* [out] */ LPWSTR *Id)
 {
     return output_unimplemented("COutputPin_QueryId", This);
 }
 
+/**
+ * \brief IPin::QueryAccept (determines can media type be accepted or not)
+ *
+ * \param[in] This  pointer to IPin interface
+ * \param[in] pmt   Media type to check
+ *
+ * \return S_OK - success
+ * \return S_FALSE - pin rejects media type
+ *
+ */
 static HRESULT STDCALL COutputPin_QueryAccept(IPin * This,
 					      /* [in] */ const AM_MEDIA_TYPE *pmt)
 {
-    return output_unimplemented("COutputPin_QueryAccept", This);
+    COutputPin* this=(COutputPin*)This;
+    Debug printf("COutputPin_QueryAccept(%p)\n", This);
+    if(memcmp(&(this->type.majortype),&(pmt->majortype),16)!=0) {
+        Debug printf("COutputPin_QueryAccept majortype differs. Rejecting(%p)\n", This);
+        return S_FALSE;
+    }
+    if(memcmp(&(this->type.subtype),&(pmt->subtype),16)!=0) {
+        Debug printf("COutputPin_QueryAccept subtype differs. Rejecting(%p)\n", This);
+        return S_FALSE;
+    }
+    if(memcmp(&pmt->formattype,&FORMAT_WaveFormatEx,16)==0 && pmt->pbFormat){
+        WAVEFORMATEX* pWF=(WAVEFORMATEX*)pmt->pbFormat;
+        if(pWF->nChannels==0) {
+            Debug printf("COutputPin_QueryAccept nChannels=0. Rejecting(%p)\n", This);
+            return S_FALSE;
+        }
+    }
+    if(memcmp(&pmt->formattype,&FORMAT_VideoInfo,16)==0 && pmt->pbFormat){
+        VIDEOINFOHEADER* Vhdr=(VIDEOINFOHEADER*)pmt->pbFormat;
+        if(Vhdr->bmiHeader.biWidth==0 && Vhdr->bmiHeader.biHeight==0) {
+            Debug printf("COutputPin_QueryAccept picture 0x0. Rejecting(%p)\n", This);
+            return S_FALSE;
+        }
+    }
+    Debug printf("COutputPin_QueryAccept(%p) Accepting following format\n", This);
+    Debug print_pmt_info(pmt);
+    return S_OK;
 }
 
+/**
+ * \brief IPin::EnumMediaTypes (enumerates the pin's preferred media types)
+ *
+ * \param[in] This  pointer to IPin interface
+ * \param[out] ppEnum adress of variable that receives pointer to IEnumMEdiaTypes interface
+ *
+ * \return S_OK - success
+ * \return E_OUTOFMEMORY - Insufficient memory
+ * \return E_POINTER     - Null pointer
+ *
+ * \note
+ * Caller must call Release on received interface when done
+ *
+ */
 static HRESULT STDCALL COutputPin_EnumMediaTypes(IPin * This,
 					   /* [out] */ IEnumMediaTypes **ppEnum)
 {
-    Debug printf("COutputPin_EnumMediaTypes() called\n");
+    Debug printf("COutputPin_EnumMediaTypes(%p) called\n",This);
     if (!ppEnum)
 	return E_INVALIDARG;
     *ppEnum = (IEnumMediaTypes*) CEnumMediaTypesCreate(&((COutputPin*)This)->type);
     return 0;
 }
 
+/**
+ * \brief IPin::QueryInternalConnections (retries pin's internal connections)
+ *
+ * \param[in]     This  pointer to IPin interface
+ * \param[out]    apPin Array that receives pins, internally connected to this
+ * \param[in,out] nPint Size of an array
+ *
+ * \return S_OK - success
+ * \return S_FALSE - pin rejects media type
+ * \return E_NOTIMPL - not implemented
+ *
+ */
 static HRESULT STDCALL COutputPin_QueryInternalConnections(IPin * This,
 						     /* [out] */ IPin **apPin,
 						     /* [out][in] */ ULONG *nPin)
@@ -270,21 +812,68 @@
     return output_unimplemented("COutputPin_QueryInternalConnections", This);
 }
 
+/**
+ * \brief IPin::EndOfStream (notifies pin, that no data is expected, until new run command)
+ *
+ * \param[in] This  pointer to IPin interface
+ *
+ * \return S_OK - success
+ * \return E_UNEXPECTED - The pin is output pin
+ *
+ * \note 
+ * IMemoryInputPin::Receive,IMemoryInputPin::ReceiveMultiple, IMemoryInputPin::EndOfStream, 
+ * IMemAllocator::GetBuffer runs in different (streaming) thread then other 
+ * methods (application thread).
+ * IMemoryInputPin::NewSegment runs either in streaming or application thread.
+ * Developer must use critical sections for thread-safing work.
+ *
+ */
 static HRESULT STDCALL COutputPin_EndOfStream(IPin * This)
 {
     return output_unimplemented("COutputPin_EndOfStream", This);
 }
 
+/**
+ * \brief IPin::BeginFlush (begins a flush operation)
+ *
+ * \param[in] This  pointer to IPin interface
+ *
+ * \return S_OK - success
+ * \return E_UNEXPECTED - The pin is output pin
+ *
+ */
 static HRESULT STDCALL COutputPin_BeginFlush(IPin * This)
 {
     return output_unimplemented("COutputPin_BeginFlush", This);
 }
 
+/**
+ * \brief IPin::EndFlush (ends a flush operation)
+ *
+ * \param[in] This  pointer to IPin interface
+ *
+ * \return S_OK - success
+ * \return E_UNEXPECTED - The pin is output pin
+ *
+ */
 static HRESULT STDCALL COutputPin_EndFlush(IPin * This)
 {
     return output_unimplemented("COutputPin_EndFlush", This);
 }
 
+/**
+ * \brief IPin::NewSegment (media sample received after this call grouped as segment with common
+ *        start,stop time and rate)
+ *
+ * \param[in] This   pointer to IPin interface
+ * \param[in] tStart start time of new segment
+ * \param[in] tStop  end time of new segment
+ * \param[in] dRate  rate at wich segment should be processed
+ *
+ * \return S_OK - success
+ * \return E_UNEXPECTED - The pin is output pin
+ *
+ */
 static HRESULT STDCALL COutputPin_NewSegment(IPin * This,
 				       /* [in] */ REFERENCE_TIME tStart,
 				       /* [in] */ REFERENCE_TIME tStop,
@@ -301,8 +890,14 @@
 
 static HRESULT STDCALL COutputPin_M_QueryInterface(IUnknown* This, const GUID* iid, void** ppv)
 {
-    COutputPin* p = (COutputPin*)This;
+    COutputMemPin* p = (COutputMemPin*)This;
 
+    /* FIXME WARN: 
+        original version does wrong type cast IMHO.
+	This is method of MemInputPin class, not COutputPin.
+	So in previous version returning pointer was containing garbage, but 
+        i'm not sure. Need additional comparation.
+    */
     Debug printf("COutputPin_M_QueryInterface(%p) called\n", This);
     if (!ppv)
 	return E_INVALIDARG;
@@ -313,17 +908,16 @@
 	p->vt->AddRef(This);
 	return 0;
     }
-    /*if(!memcmp(iid, &IID_IPin, 16))
+    if(!memcmp(iid, &IID_IPin, 16))
     {
-	COutputPin* ptr=(COutputPin*)(This-1);
-	*ppv=(void*)ptr;
-	AddRef((IUnknown*)ptr);
+	*ppv = p->parent; //COutputPin
+	p->parent->vt->AddRef((IUnknown*)p->parent);
 	return 0;
-    }*/
+    }
     if(!memcmp(iid, &IID_IMemInputPin, 16))
     {
-	*ppv = p->mempin;
-	p->mempin->vt->AddRef(This);
+	*ppv = This;
+	This->vt->AddRef(This);
 	return 0;
     }
     Debug printf("Unknown interface : %08x-%04x-%04x-%02x%02x-" \
@@ -338,37 +932,189 @@
 
 // IMemInputPin methods
 
-static HRESULT STDCALL COutputPin_GetAllocator(IMemInputPin* This,
+
+/**
+ * \brief IMemInputPin::GetAllocator (retrives memory allocator, proposed by pin)
+ *
+ * \param[in]  This pointer to IMemInputPin interface
+ * \param[out]  ppAllocator  address of variable that receives allocator's IMemAllocator interface
+ *
+ * \return S_OK - success
+ * \return VFW_E_NO_ALLOCATOR - No allocator
+ *
+ * \note
+ * Make sure to call Release on received interface when you are done
+ *
+ */
+static HRESULT STDCALL COutputMemPin_GetAllocator(IMemInputPin* This,
 					 /* [out] */ IMemAllocator** ppAllocator)
 {
-    Debug printf("COutputPin_GetAllocator(%p, %p) called\n", This->vt, ppAllocator);
-    *ppAllocator = (IMemAllocator*) MemAllocatorCreate();
+    COutputMemPin* this=(COutputMemPin*)This;
+    Debug printf("COutputMemPin_GetAllocator(%p, %p) called\n", this, this->pAllocator);
+    // DirectShow provide us it's own allocator later, if necessery
+    if(!this->pAllocator) this->pAllocator=(IMemAllocator*)MemAllocatorCreate();
+    this->pAllocator->vt->AddRef((IUnknown*)this->pAllocator);
+    *ppAllocator = this->pAllocator;
     return 0;
 }
 
-static HRESULT STDCALL COutputPin_NotifyAllocator(IMemInputPin* This,
+/**
+ *
+ * \brief IMemInputPin::NotifyAllocator (specifies an allocator for the connection)
+ *
+ * \param[in]  This pointer to IMemInputPin interface
+ * \param[in]  pAllocator  allocator's IMemAllocator interface
+ * \param[in]  bReadOnly specifies whether samples from allocator are readonly
+ *
+ * \return S_OK - success
+ * \return Apropriate error code otherwise
+ *
+ */
+static HRESULT STDCALL COutputMemPin_NotifyAllocator(IMemInputPin* This,
 						  /* [in] */ IMemAllocator* pAllocator,
 						  /* [in] */ int bReadOnly)
 {
-    Debug printf("COutputPin_NotifyAllocator(%p, %p) called\n", This, pAllocator);
-    ((COutputMemPin*)This)->pAllocator = (MemAllocator*) pAllocator;
+    COutputMemPin* this=(COutputMemPin*)This;    
+    ALLOCATOR_PROPERTIES props;
+    Debug printf("COutputMemPin_NotifyAllocator(%p, %p => %p) called\n", This, this->pAllocator,pAllocator);
+    if (this->pAllocator && this->pAllocator != pAllocator){
+        //Remote pin suggest another allocator; => removing old one
+        this->pAllocator->vt->Release((IUnknown*)this->pAllocator);
+    }
+    this->pAllocator = pAllocator;
+    this->pAllocator->vt->AddRef((IUnknown*)this->pAllocator); //-- seem like we not need this
+
+    this->pAllocator->vt->GetProperties(this->pAllocator,&props);
+#if defined(HAVE_TV_DSHOW)
+    init_ringbuffer(this,props.cBuffers,props.cbBuffer);
+#endif
     return 0;
 }
 
-static HRESULT STDCALL COutputPin_GetAllocatorRequirements(IMemInputPin* This,
+/**
+ * \brief IMemInputPin::GetAllocatorRequirements (retrieves allocator properties requested by
+ *        input pin)
+ *
+ * \param[in]  This pointer to IMemInputPin interface
+ * \param[out]  pProps pointer to a structure that receives allocator properties
+ *
+ * \return S_OK - success
+ * \return E_NOTIMPL - Not implemented
+ * \return E_POINTER - Null pointer
+ *
+ */
+static HRESULT STDCALL COutputMemPin_GetAllocatorRequirements(IMemInputPin* This,
 							   /* [out] */ ALLOCATOR_PROPERTIES* pProps)
 {
-    return output_unimplemented("COutputPin_GetAllocatorRequirements", This);
+    return output_unimplemented("COutputMemPin_GetAllocatorRequirements", This);
 }
 
-static HRESULT STDCALL COutputPin_Receive(IMemInputPin* This,
+
+#if defined(HAVE_TV_DSHOW)
+static int COutputPin_FillBuffer(COutputPin* This,char* buffer,int len,long long* ppts,long long*psampleno){
+    int bytes;
+    COutputMemPin* mp=This->mempin;
+    Debug printf("COutputPin_FillBuffer(%p) (%d/%d) called \n", This,mp->count,mp->buffersize);
+    if(!mp->ringbuffer || !mp->count) return 0; //underrrun
+
+    if (len<mp->blocksize) 
+        bytes=len;
+    else 
+        bytes=mp->blocksize;
+    memcpy(buffer,mp->ringbuffer[mp->head],bytes);
+    if (ppts) *ppts=mp->pts[mp->head];
+    if (psampleno) *psampleno=mp->sampleno[mp->head];
+    EnterCriticalSection(&(mp->crit));
+      mp->head=(mp->head+1)%mp->buffersize;
+      mp->count--;
+    LeaveCriticalSection(&(mp->crit));
+    return bytes;
+}
+/**
+ * \brief copies media data, sample number and timestamp from given media sample to 
+ *        internal ringbuffer
+ *
+ * \param[in]  this pointer to COutputMemPin object
+ * \param[out] pSample media sample to copy data from 
+ *
+ * TOTO: add proper error/warning messages
+ *
+ */
+static void CopySample(COutputMemPin* this,IMediaSample* pSample){
+    int bytes;
+    unsigned char* pointer;
+    long long start,end;
+    if(!this->ringbuffer) return ;
+    if(this->count>=this->buffersize) {
+        printf ("CopySample(%p) Buffer full! Loosing frame (block=%d ring=%d)!\n",this,this->blocksize,this->buffersize);
+        return ;
+    }
+
+    //data
+    bytes=pSample->vt->GetActualDataLength(pSample);
+    if(bytes>this->blocksize) bytes=this->blocksize; //FIXME: overflow!!
+    pSample->vt->GetPointer(pSample,&pointer);
+    memcpy(this->ringbuffer[this->tail],pointer,bytes);
+
+    //timestamp
+    start=end=0;
+    pSample->vt->GetTime(pSample,&start,&end);
+    Debug printf("CopySample(%p) called time=(%lld,%lld) \n", this,start,end);
+    this->pts[this->tail]=end; //probably need "end"
+    //sample number
+    start=end=0;
+    pSample->vt->GetMediaTime(pSample,&start,&end);
+    Debug printf("CopySample(%p) called mtime=(%lld,%lld) \n", this,start,end);
+    this->sampleno[this->tail]=start;
+
+    EnterCriticalSection(&(this->crit));
+      this->tail=(this->tail+1)%this->buffersize;
+      this->count++;
+    LeaveCriticalSection(&(this->crit));
+}
+#endif
+/**
+ * \brief IMemInputPin::Receive (receives the next media sample int thre stream)
+ *
+ * \param[in]  This pointer to IMemInputPin interface
+ * \param[in]  pSample pointer to sample's IMediaSample interface
+ *
+ * \return S_OK - success
+ * \return S_FALSE - The sample was rejected
+ * \return E_POINTER - Null pointer
+ * \return VFW_E_INVALIDMEDIATYPE - invalid media type
+ * \return VFW_E_RUNTIME_ERROR - run-time error occured
+ * \return VFW_E_WRONG_STATE - pin is stopped
+ *
+ * \remarks
+ * Method san do on of the following:
+ * - reject sample
+ * - accept sample and process it in another thread
+ * - accept sample and process it before returning
+ *
+ * In second case method should increase reference count for sample (through AddRef)
+ * In the last case method might block indefinitely. If this might
+ * happen IMemInpuPin::ReceiveCAnBlock returns S_OK
+ *
+ * \note 
+ * IMemoryInputPin::Receive,IMemoryInputPin::ReceiveMultiple, IMemoryInputPin::EndOfStream, 
+ * IMemAllocator::GetBuffer runs in different (streaming) thread then other 
+ * methods (application thread).
+ * IMemoryInputPin::NewSegment runs either in streaming or application thread.
+ * Developer must use critical sections for thread-safing work.
+ *
+ */
+static HRESULT STDCALL COutputMemPin_Receive(IMemInputPin* This,
 					  /* [in] */ IMediaSample* pSample)
 {
     COutputMemPin* mp = (COutputMemPin*)This;
+    IReferenceClock* pClock=NULL;
+    REFERENCE_TIME pts;
+    HRESULT hr;
     char* pointer;
     int len;
 
-    Debug printf("COutputPin_Receive(%p) called\n", This);
+    Debug printf("COutputMemPin_Receive(%p) called\n", This);
     if (!pSample)
 	return E_INVALIDARG;
     if (pSample->vt->GetPointer(pSample, (BYTE**) &pointer))
@@ -382,6 +1128,10 @@
 	*(mp->frame_pointer) = pointer;
     if (mp->frame_size_pointer)
 	*(mp->frame_size_pointer) = len;
+
+#if defined(__MINGW32__)
+    CopySample(mp,pSample);
+#endif
 /*
     FILE* file=fopen("./uncompr.bmp", "wb");
     char head[14]={0x42, 0x4D, 0x36, 0x10, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00};
@@ -396,43 +1146,134 @@
     return 0;
 }
 
-static HRESULT STDCALL COutputPin_ReceiveMultiple(IMemInputPin * This,
+/**
+ * \brief IMemInputPin::ReceiveMultiple (receives multiple samples in the stream)
+ *
+ * \param[in]  This pointer to IMemInputPin interface
+ * \param[in]  pSamples          pointer to array with samples
+ * \param[in]  nSamples          number of samples in array
+ * \param[out] nSamplesProcessed number of processed samples
+ *
+ * \return S_OK - success
+ * \return S_FALSE - The sample was rejected
+ * \return E_POINTER - Null pointer
+ * \return VFW_E_INVALIDMEDIATYPE - invalid media type
+ * \return VFW_E_RUNTIME_ERROR - run-time error occured
+ * \return VFW_E_WRONG_STATE - pin is stopped
+ *
+ * \remarks
+ * This method behaves like IMemInputPin::Receive but for array of samples
+ *
+ * \note 
+ * IMemoryInputPin::Receive,IMemoryInputPin::ReceiveMultiple, IMemoryInputPin::EndOfStream, 
+ * IMemAllocator::GetBuffer runs in different (streaming) thread then other 
+ * methods (application thread).
+ * IMemoryInputPin::NewSegment runs either in streaming or application thread.
+ * Developer must use critical sections for thread-safing work.
+ *
+ */
+static HRESULT STDCALL COutputMemPin_ReceiveMultiple(IMemInputPin * This,
 					    /* [size_is][in] */ IMediaSample **pSamples,
 					    /* [in] */ long nSamples,
 					    /* [out] */ long *nSamplesProcessed)
 {
-    return output_unimplemented("COutputPin_ReceiveMultiple", This);
+    HRESULT hr;
+    Debug printf ("COutputMemPin_ReceiveMultiple(%p) %d\n", This,nSamples);
+    *nSamplesProcessed = 0;
+    while (nSamples-- > 0) {
+         hr = This->vt->Receive(This,pSamples[*nSamplesProcessed]);
+         if (hr != S_OK) break;
+         (*nSamplesProcessed)++;
+    }
+    return hr;
 }
 
-static HRESULT STDCALL COutputPin_ReceiveCanBlock(IMemInputPin * This)
+/**
+ * \brief IMemInputPin::ReceiveCanBlock (determines whether IMemInputPin:::Receive might block)
+ *
+ * \param[in]  This pointer to IMemInputPin interface
+ *
+ * \return S_OK - the pin might block
+ * \return S_FALSE - the pin will not block
+ *
+ */
+static HRESULT STDCALL COutputMemPin_ReceiveCanBlock(IMemInputPin * This)
 {
-    return output_unimplemented("COutputPin_ReceiveCanBlock", This);
+    return output_unimplemented("COutputMemPin_ReceiveCanBlock", This);
 }
 
+/**
+ * \brief COutputPin::SetFramePointer (sets internal frame pointer to an external buffer)
+ *
+ * \param[in]  This pointer to COutputPin class
+ * \param[in]  z    new pointer
+ *
+ */
 static void COutputPin_SetFramePointer(COutputPin* This, char** z)
 {
     This->mempin->frame_pointer = z;
 }
 
+/**
+ * \brief COutputPin::SetFramePointer2 (sets allocator's pointer to an external buffer)
+ *
+ * \param[in]  This pointer to COutputPin class
+ * \param[in]  z    new pointer
+ *
+ */
 static void COutputPin_SetPointer2(COutputPin* This, char* p)
 {
     if (This->mempin->pAllocator)
-        // fixme
-	This->mempin->pAllocator->SetPointer(This->mempin->pAllocator, p);
+	((MemAllocator*)This->mempin->pAllocator)->SetPointer((MemAllocator*)This->mempin->pAllocator, p);
 }
 
+/**
+ * \brief COutputPin::SetFrameSizePointer (sets pointer to variable that receives frame size)
+ *
+ * \param[in]  This pointer to COutputPin class
+ * \param[in]  z    new pointer
+ *
+ */
 static void COutputPin_SetFrameSizePointer(COutputPin* This, long* z)
 {
     This->mempin->frame_size_pointer = z;
 }
 
+
+/**
+ * \brief COutputPin::SetNewFormat(sets new media format for the pin)
+ *
+ * \param[in]  This pointer to COutputPin class
+ * \param[in]  amt  new media format
+ *
+ */
 static void COutputPin_SetNewFormat(COutputPin* This, const AM_MEDIA_TYPE* amt)
 {
-    This->type = *amt;
+    free_media_type(&(This->type)); //Free pbFormat and pUnk
+    /* FIXME: this may fail and also we must Check and Reconnect  pins with new format */
+    copy_media_type(&(This->type),amt);
 }
 
+/**
+ * \brief COutputPin destructor
+ *
+ * \param[in]  This pointer to COutputPin class
+ *
+ */
 static void COutputPin_Destroy(COutputPin* This)
 {
+    Debug printf("COutputPin_Destroy(%p) called\n",This);
+
+#if defined(__MINGW32__)
+    free_ringbuffer(This->mempin);
+#endif
+
+    if(This->remote){
+        This->remote->vt->Release((IUnknown*)This->remote);
+        This->remote=NULL;
+    }
+
+    free_media_type(&(This->type));
     if (This->mempin->vt)
 	free(This->mempin->vt);
     if (This->mempin)
@@ -442,6 +1283,14 @@
     free(This);
 }
 
+/**
+ * \brief IUnknown::AddRef (increases reference counter for interface)
+ *
+ * \param[in]  This pointer to IUnknown class
+ *
+ * \return S_OK success
+ *
+ */
 static HRESULT STDCALL COutputPin_AddRef(IUnknown* This)
 {
     Debug printf("COutputPin_AddRef(%p) called (%d)\n", This, ((COutputPin*)This)->refcount);
@@ -449,6 +1298,17 @@
     return 0;
 }
 
+/**
+ * \brief IUnknown::Release (desreases reference counter for interface)
+ *
+ * \param[in]  This pointer to IUnknown class
+ *
+ * \return S_OK - success
+ *
+ * \remarks
+ * When reference counter reaches zero calls destructor
+ *
+ */
 static HRESULT STDCALL COutputPin_Release(IUnknown* This)
 {
     Debug printf("COutputPin_Release(%p) called (%d)\n", This, ((COutputPin*)This)->refcount);
@@ -458,28 +1318,59 @@
     return 0;
 }
 
-static HRESULT STDCALL COutputPin_M_AddRef(IUnknown* This)
+/**
+ * \brief IUnknown::AddRef (increases reference counter for interface)
+ *
+ * \param[in]  This pointer to IUnknown class
+ *
+ * \return S_OK - success
+ *
+ */
+static HRESULT STDCALL COutputMemPin_AddRef(IUnknown* This)
 {
     COutputMemPin* p = (COutputMemPin*) This;
-    Debug printf("COutputPin_MAddRef(%p) called (%p, %d)\n", p, p->parent, p->parent->refcount);
+    Debug printf("COutputMemPin_AddRef(%p) called (%p, %d)\n", p, p->parent, p->parent->refcount);
     p->parent->refcount++;
     return 0;
 }
 
-static HRESULT STDCALL COutputPin_M_Release(IUnknown* This)
+/**
+ * \brief IUnknown::Release (desreases reference counter for interface)
+ *
+ * \param[in]  This pointer to IUnknown class
+ *
+ * \return S_OK - success
+ *
+ * \remarks
+ * When reference counter reaches zero calls destructor
+ *
+ */
+static HRESULT STDCALL COutputMemPin_Release(IUnknown* This)
 {
     COutputMemPin* p = (COutputMemPin*) This;
-    Debug printf("COutputPin_MRelease(%p) called (%p,   %d)\n",
+    Debug printf("COutputMemPin_Release(%p) called (%p,   %d)\n",
 		 p, p->parent, p->parent->refcount);
     if (--p->parent->refcount <= 0)
 	COutputPin_Destroy(p->parent);
     return 0;
 }
 
-COutputPin* COutputPinCreate(const AM_MEDIA_TYPE* amt)
+/**
+ * \brief COutputPin constructor
+ *
+ * \param[in]  amt media type for pin
+ *
+ * \return pointer to COutputPin if success
+ * \return NULL if error occured
+ *
+ */
+COutputPin* COutputPinCreate(const AM_MEDIA_TYPE* amt,IBaseFilter* parent)
 {
+    IMemInputPin_vt* ivt;
     COutputPin* This = (COutputPin*) malloc(sizeof(COutputPin));
-    IMemInputPin_vt* ivt;
+    if (!parent)
+        return NULL;
+    printf("%s called\n", "COutputPinCreate");
 
     if (!This)
         return NULL;
@@ -494,11 +1385,12 @@
 	return NULL;
     }
 
+    This->pFilter=parent;
     This->mempin->vt = ivt;
 
     This->refcount = 1;
     This->remote = 0;
-    This->type = *amt;
+    copy_media_type(&(This->type),amt);
 
     This->vt->QueryInterface = COutputPin_QueryInterface;
     This->vt->AddRef = COutputPin_AddRef;
@@ -520,25 +1412,34 @@
     This->vt->NewSegment = COutputPin_NewSegment;
 
     This->mempin->vt->QueryInterface = COutputPin_M_QueryInterface;
-    This->mempin->vt->AddRef = COutputPin_M_AddRef;
-    This->mempin->vt->Release = COutputPin_M_Release;
-    This->mempin->vt->GetAllocator = COutputPin_GetAllocator;
-    This->mempin->vt->NotifyAllocator = COutputPin_NotifyAllocator;
-    This->mempin->vt->GetAllocatorRequirements = COutputPin_GetAllocatorRequirements;
-    This->mempin->vt->Receive = COutputPin_Receive;
-    This->mempin->vt->ReceiveMultiple = COutputPin_ReceiveMultiple;
-    This->mempin->vt->ReceiveCanBlock = COutputPin_ReceiveCanBlock;
+    This->mempin->vt->AddRef = COutputMemPin_AddRef;
+    This->mempin->vt->Release = COutputMemPin_Release;
+    This->mempin->vt->GetAllocator = COutputMemPin_GetAllocator;
+    This->mempin->vt->NotifyAllocator = COutputMemPin_NotifyAllocator;
+    This->mempin->vt->GetAllocatorRequirements = COutputMemPin_GetAllocatorRequirements;
+    This->mempin->vt->Receive = COutputMemPin_Receive;
+    This->mempin->vt->ReceiveMultiple = COutputMemPin_ReceiveMultiple;
+    This->mempin->vt->ReceiveCanBlock = COutputMemPin_ReceiveCanBlock;
 
     This->mempin->frame_size_pointer = 0;
     This->mempin->frame_pointer = 0;
     This->mempin->pAllocator = 0;
     This->mempin->refcount = 1;
     This->mempin->parent = This;
-
+#if defined(HAVE_TV_DSHOW)
+    This->mempin->blocksize=0;
+    This->mempin->buffersize=0;
+    This->mempin->ringbuffer=NULL;
+    This->mempin->sampleno=NULL;
+    This->mempin->pts=NULL;
+#endif
     This->SetPointer2 = COutputPin_SetPointer2;
     This->SetFramePointer = COutputPin_SetFramePointer;
     This->SetFrameSizePointer = COutputPin_SetFrameSizePointer;
     This->SetNewFormat = COutputPin_SetNewFormat;
+#if defined(HAVE_TV_DSHOW)
+    This->FillBuffer=COutputPin_FillBuffer;
+#endif
 
     return This;
 }
Index: loader/dshow/outputpin.h
===================================================================
--- loader/dshow/outputpin.h	(revision 21934)
+++ loader/dshow/outputpin.h	(working copy)
@@ -15,12 +15,22 @@
     COutputMemPin* mempin;
     AM_MEDIA_TYPE type;
     IPin* remote;
+    IBaseFilter* pFilter;
     void ( *SetFramePointer )(COutputPin*, char** z);
     void ( *SetPointer2 )(COutputPin*, char* p);
     void ( *SetFrameSizePointer )(COutputPin*, long* z);
     void ( *SetNewFormat )(COutputPin*, const AM_MEDIA_TYPE* a);
+#if defined(HAVE_TV_DSHOW)
+    int  ( *FillBuffer)(COutputPin*,char* ,int ,long long* ,long long*);
+#endif
 };
 
-COutputPin* COutputPinCreate(const AM_MEDIA_TYPE* vhdr);
+COutputPin* COutputPinCreate(const AM_MEDIA_TYPE* vhdr,IBaseFilter* parent);
 
+void print_pmt_info(const AM_MEDIA_TYPE* pmt);
+void free_media_type(AM_MEDIA_TYPE* pmt);
+void delete_media_type(AM_MEDIA_TYPE* pmt);
+HRESULT copy_media_type(AM_MEDIA_TYPE* pDst,const AM_MEDIA_TYPE* pSrc);
+AM_MEDIA_TYPE* create_media_type(const AM_MEDIA_TYPE* pSrc);
+
 #endif /* DS_OUTPUTPIN_H */
Index: loader/Makefile
===================================================================
--- loader/Makefile	(revision 21934)
+++ loader/Makefile	(working copy)
@@ -29,6 +29,10 @@
        dmo/dmo.c  \
        dmo/dmo_guids.c \
 
+ifeq ($(TV_DSHOW),yes)
+SRCS+= dshow/DS_MPGrabber.c
+endif
+
 include ../mpcommon.mak
 
 CFLAGS+=-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer
Index: stream/Makefile
===================================================================
--- stream/Makefile	(revision 21934)
+++ stream/Makefile	(working copy)
@@ -52,6 +52,7 @@
 SRCS-$(TV_BSDBT848)       += tvi_bsdbt848.c
 SRCS-$(TV_V4L1)           += tvi_v4l.c  audio_in.c
 SRCS-$(TV_V4L2)           += tvi_v4l2.c audio_in.c
+SRCS-$(TV_DSHOW)          += tvi_dshow.c
 SRCS-$(VCD)               += stream_vcd.c
 SRCS-$(VSTREAM)           += stream_vstream.c
 
Index: stream/tv.c
===================================================================
--- stream/tv.c	(revision 21934)
+++ stream/tv.c	(working copy)
@@ -636,11 +636,16 @@
 tvi_handle_t *tvi_init_v4l(char *device, char *adevice);
 tvi_handle_t *tvi_init_v4l2(char *device, char *adevice);
 tvi_handle_t *tvi_init_bsdbt848(char *device);
+tvi_handle_t *tvi_init_dshow(char *device);
 
 tvi_handle_t *tv_begin(void)
 {
     if (!strcmp(tv_param_driver, "dummy"))
 	return tvi_init_dummy(tv_param_device);
+#ifdef HAVE_TV_DSHOW
+    if (!strcmp(tv_param_driver, "dshow"))
+	return tvi_init_dshow(tv_param_device);
+#endif
 #ifdef HAVE_TV_V4L1
     if (!strcmp(tv_param_driver, "v4l"))
 	return tvi_init_v4l(tv_param_device, tv_param_adevice);
@@ -653,6 +658,10 @@
     if (!strcmp(tv_param_driver, "bsdbt848"))
 	return tvi_init_bsdbt848(tv_param_device);
 #endif
+#ifdef HAVE_TV_DSHOW
+    if (!strcmp(tv_param_driver, "dshow"))
+	return tvi_init_dshow(tv_param_device);
+#endif
 
     mp_msg(MSGT_TV, MSGL_ERR, "No such driver: %s\n", tv_param_driver); 
     return(NULL);
Index: stream/tvi_dshow.c
===================================================================
--- stream/tvi_dshow.c	(revision 0)
+++ stream/tvi_dshow.c	(revision 0)
@@ -0,0 +1,1299 @@
+/*
+ *     TV support under Win32
+ * 
+ *     Initially wrote by Vladimir Voroshilov <voroshil at gmail.com>.
+ *     Based on tvi_dummy.c with help of tv.c, tvi_v4l2.c and /loader/dshow/ 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)
+ *
+ *     Disadvantages:
+ *     * Audio only capture does not supported.
+ *     * Pausing or moving video windows causes buffer overflow (no pause callback).
+ *     * Supports fine only IMGFMT_YUY2 (BGR formats cause garbage input, trouble somewhere in code)
+ *     * Sets channels only by it's number, not by freq, so durty hack is used
+ *     * Uses frequency table hack to access,.
+ *     * Tested only with LifeView FlyTV Prime 34FM (SAA7134 based) with driver from Ivan Uskov
+ *     * Code potentually can be used for radio support, but due to bug in the driver can not be tested
+ *
+ *     TODO:
+ *     * rewrite startup parameters negotiation
+ *     * Set default format from a one of available, then get parameters through ioctl,attepmt to set resulted format 
+ *        and exit if failure.
+ *     * Frequency table selecting (and remove 'tvh' hack )
+ *     * Flip image upside-down for RGB formats. 
+ *     * check using header files and keep only needed
+ *     * Move some code from init() to start() (because there some parameters (formats,...) already negotiated
+ *     * Add some notes to methods' parameters
+ *     * replace parameter from V4L style frequency to Hz in get_frequency and set_frequency
+ *     * make crossbar configurable
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include "libmpcodecs/img_format.h"
+#include "libaf/af_format.h"
+
+#include "loader/com.h"
+#include "loader/wine/mmreg.h"
+#include "loader/dshow/DS_MPGrabber.h"
+#include "loader/dshow/guids.h"
+
+#ifndef NOAVIFILE_HEADERS
+#define VFW_E_NOT_RUNNING               0x80040226
+#define VFW_E_NO_ALLOCATOR              0x8004020A
+#else
+#include "libwin32.h"
+#endif
+
+#include "tv.h"
+#include "mp_msg.h"
+#include "frequencies.h"
+
+
+#include "tvi_dshow.h"
+
+
+#define MY_PIN_CATEGORY PIN_CATEGORY_CAPTURE
+
+const GUID IID_IKsPropertySet={0x31efac30, 0x515c, 0x11d0, 
+    {0xa9,0xaa, 0x00,0xaa,0x00,0x61,0xbe,0x93}};
+    
+
+/*====== REVIEWED CODE BEGIN ============================*/
+/* information about this file */
+static tvi_info_t info = {
+	"DirectShow TV",
+	"dshow",
+	"voroshil",
+	"Very experimental!! Use with caution"
+};
+
+typedef struct {
+    int dev_index;            ///< capture device index in device list (defaul: 0, dirst available device)
+    int dev_pin;              ///< currently using for debug pruposes, can be used for selecting audio capture device
+    int state;                ///< state: 1-filter graph running, 0-filter graph stopped
+
+    int fcc;                  ///< used video format code (FourCC)
+    int width;                ///< picture width (default: 320) 
+    int height;               ///< picture height (default: 240)
+    int samplerate;           ///< audio samplerate (default: 44100)
+    //would be fixed/removed in future
+    tvi_handle_t* tvh;        ///< FIXME: hack to access frequency table
+
+    // DirectShow related stuff
+    AM_MEDIA_TYPE* pmtVideo;  ///< DirectShow video stream properties
+    AM_MEDIA_TYPE* pmtAudio;  ///< DirectShow audio stream properties. NULL mean audio disabled.
+    IAMTVTuner 			* pTVTuner;        ///< interface for tuner device
+    IGraphBuilder 		* pGraph;          ///< filter graph
+    ICaptureGraphBuilder2	* pBuilder;        ///< graph builder
+    IBaseFilter           	* pBaseFilter;     ///< interface for capture device
+    DS_MPGrabber                * pGrabber;        ///< MPlayer's grabber filter
+    IMediaControl               * pMediaControl;   ///< interface for controlling graph (start, stop,...)
+} priv_t;
+
+#include "tvi_def.h"
+/*====== REVIEWED CODE END ============================*/
+
+const GUID CLSID_CaptureGraphBuilder={0xBF87B6E0, 0x8C27, 0x11d0, 
+    { 0xB3, 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5}};
+const GUID CLSID_CaptureGraphBuilder2={0xBF87B6E1, 0x8C27, 0x11d0, 
+    { 0xB3, 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5}};
+const GUID CLSID_FilterGraph={0xe436ebb3, 0x524f, 0x11ce, 
+    { 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
+const GUID CLSID_SystemDeviceEnum={0x62BE5D10, 0x60EB, 0x11d0, 
+    { 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86}};
+const GUID CLSID_VideoInputDeviceCategory={0x860BB310, 0x5D01, 0x11d0, 
+    { 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86}};
+const GUID CLSID_AudioInputDeviceCategory={0x33d9a762, 0x90c8, 0x11d0, 
+    { 0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86}};
+
+const GUID IID_IAMTVTuner={0x211A8766, 0x03AC, 0x11d1, 
+    { 0x8D, 0x13, 0x00, 0xAA, 0x00, 0xBD, 0x83, 0x39}};
+const GUID IID_IAMCrossbar={0xc6e13380, 0x30ac, 0x11d0, 
+    { 0xa1, 0x8c, 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56}};
+const GUID IID_ICaptureGraphBuilder={0xbf87b6e0, 0x8c27, 0x11d0, 
+    { 0xb3, 0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5}};
+const GUID IID_ICaptureGraphBuilder2={0x93e5a4e0, 0x2d50, 0x11d2, 
+    { 0xab, 0xfa, 0x00, 0xa0, 0xc9, 0xc6, 0xe3, 0x8d}};
+const GUID IID_IFilterGraph={0x56a8689f, 0x0ad4, 0x11ce, 
+    { 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
+const GUID IID_ICreateDevEnum={0x29840822, 0x5b84, 0x11d0, 
+    { 0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86}};
+const GUID IID_IPropertyBag={0x55272a00, 0x42cb, 0x11ce, 
+    { 0x81, 0x35, 0x00, 0xaa, 0x00, 0x4b, 0xb8, 0x51}};
+const GUID IID_IMediaControl={0x56a868b1, 0x0ad4, 0x11ce, 
+    { 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
+const GUID IID_IGraphBuilder={0x56a868a9, 0x0ad4, 0x11ce, 
+    { 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
+
+const GUID PIN_CATEGORY_CAPTURE={0xfb6c4281, 0x0353, 0x11d1, 
+    {0x90, 0x5f, 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba}};
+const GUID PIN_CATEGORY_PREVIEW={0xfb6c4282, 0x0353, 0x11d1, 
+    {0x90, 0x5f, 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba}};
+
+
+struct tvi_indexed_string {
+    long index;
+    char* name;
+};
+
+typedef struct  {
+    uint32_t fmt;
+    const GUID* subtype;
+    int nBits;
+    int nCompression;
+    int tail;
+} img_fmt ;
+
+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}
+};
+
+AM_MEDIA_TYPE* create_video_type(int fmt){
+    AM_MEDIA_TYPE* pmt;
+    VIDEOINFOHEADER* Vhdr;
+    int index;
+
+    pmt=(AM_MEDIA_TYPE*)malloc(sizeof(AM_MEDIA_TYPE));
+    if(!pmt) return NULL;
+
+    memset(pmt,0,sizeof(AM_MEDIA_TYPE));
+
+    pmt->majortype=MEDIATYPE_Video;
+    pmt->bFixedSizeSamples=1;
+
+    for(index=0;img_fmt_list[index].fmt;index++)
+        if(img_fmt_list[index].fmt==fmt) break;
+    
+    pmt->subtype=*img_fmt_list[index].subtype;
+
+    return pmt;
+}
+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)) return img_fmt_list[i].fmt;
+    }
+    return 0;
+}
+
+#if 0
+AM_MEDIA_TYPE* GetMediaType(int width,int height,int fmt){
+    return create_video_type(fmt);
+}
+#endif
+#define TV_NORMS_COUNT 19
+const struct tvi_indexed_string 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"}
+};
+long tv_available_norms[TV_NORMS_COUNT];
+int tv_available_norms_count=0;
+
+     typedef struct
+     {
+         WORD CountryCode;
+         WORD CableFreqTable;
+         WORD BroadcastFreqTable;
+         DWORD VideoStandard;
+     } TRCCountryList;
+ 
+
+/* stub */
+#define TV_INPUTS_COUNT 1
+const struct tvi_indexed_string tv_inputs[TV_INPUTS_COUNT]={
+    {1,"Television"}
+};
+long tv_available_inputs[TV_NORMS_COUNT];
+int tv_available_inputs_count=0;
+
+
+/* Forward declaration of private methods  */
+int setFreq(priv_t* priv,long lFreq);
+AM_MEDIA_TYPE* GetMediaType(int width,int height,int fmt);
+HRESULT SetVCrossbar(ICaptureGraphBuilder2* pBuilder,IBaseFilter* pBaseFilter);
+AM_MEDIA_TYPE* create_audio_media_type(int samplerate,int bits,int channels);
+
+HRESULT display_device_media_types(priv_t* priv,GUID* pmediatype){
+    IEnumMediaTypes* pEnum;
+    IPin* pPin;
+    int i;
+    ULONG cFetched;
+    AM_MEDIA_TYPE* pmt;
+    HRESULT hr;
+
+    hr=priv->pBuilder->vt->FindPin(priv->pBuilder,priv->pBaseFilter,PINDIR_OUTPUT,NULL,pmediatype,FALSE,0,&pPin);
+    if(FAILED(hr)) return hr;
+
+    hr=pPin->vt->EnumMediaTypes(pPin,&pEnum);
+    pPin->vt->Release((IUnknown*)pPin);
+    if(FAILED(hr)) return hr;
+    
+    for (i=0;pEnum->vt->Next(pEnum,1, &pmt,&cFetched)==S_OK;i++) {
+        if(!pmt) break;
+
+        print_pmt_info(pmt);
+        delete_media_type(pmt);
+    }
+    pEnum->vt->Release((IUnknown*)pEnum);
+    return S_OK;
+}
+
+/**
+    TODO: recheck code
+*/
+HRESULT set_media_format(priv_t* priv, AM_MEDIA_TYPE* pmt){
+    IPin* pRemotePin;
+    COutputPin* pPin;
+    HRESULT hr;
+    int result=S_OK;
+    int isVideo=0;
+    AM_MEDIA_TYPE* pmt2;
+
+    if(!pmt) return E_POINTER;
+
+    if(memcmp(&(pmt->majortype),&MEDIATYPE_Video,16)==0)
+        isVideo=1;
+
+    mp_msg(MSGT_TV,MSGL_V,"Requesting following %s format:\n",isVideo?"video":"audio");
+    print_pmt_info(pmt);
+    
+    hr=priv->pBuilder->vt->FindPin(priv->pBuilder,priv->pGrabber,PINDIR_INPUT,NULL,isVideo?&MEDIATYPE_Video:&MEDIATYPE_Audio,FALSE,0,&pPin);
+    if(FAILED(hr)) return hr;
+
+    pPin->vt->ConnectedTo(pPin,&pRemotePin);
+    if(hr==S_OK && pRemotePin) //S_OK is mandatory here
+    {
+        hr=priv->pGraph->vt->Disconnect(priv->pGraph,pPin);        
+        if(FAILED(hr))
+        {
+            pPin->vt->Release((IUnknown*)pPin);
+            pRemotePin->vt->Release((IUnknown*)pRemotePin);
+            return hr;
+        }
+        hr=priv->pGraph->vt->Disconnect(priv->pGraph,pRemotePin);        
+        if(FAILED(hr))
+        {
+            pPin->vt->Release((IUnknown*)pPin);
+            pRemotePin->vt->Release((IUnknown*)pRemotePin);
+            return hr;
+        }
+        hr=pRemotePin->vt->QueryAccept(pRemotePin,pmt);
+        if(hr!=S_OK){
+            mp_msg(MSGT_TV,MSGL_WARN,"Format %s not accepted by remote pin\n",isVideo?"video":"audio");
+            result=hr; //Remote pin accepts this type
+        }
+        pRemotePin->vt->Release((IUnknown*)pRemotePin);
+    }
+    if(result==S_OK) 
+        pPin->SetNewFormat(pPin,pmt);
+
+    hr=priv->pBuilder->vt->RenderStream(priv->pBuilder,&MY_PIN_CATEGORY, isVideo?&MEDIATYPE_Video:&MEDIATYPE_Audio,(IUnknown*)priv->pBaseFilter, NULL, (IBaseFilter*)priv->pGrabber);
+    if(FAILED(hr)) {
+        mp_msg(MSGT_TV,MSGL_ERR,"Rebuilding %s chain in graph failure. Error=0x%08x",isVideo?"video":"audio",hr);
+        result=hr;
+    }
+    if(isVideo){
+        if(!priv->pmtVideo){
+            priv->pmtVideo=(AM_MEDIA_TYPE*)malloc(sizeof(AM_MEDIA_TYPE));
+            memset(priv->pmtVideo,0,sizeof(AM_MEDIA_TYPE));
+        }
+    }else{
+        if(!priv->pmtAudio){
+            priv->pmtAudio=(AM_MEDIA_TYPE*)malloc(sizeof(AM_MEDIA_TYPE));
+            memset(priv->pmtVideo,0,sizeof(AM_MEDIA_TYPE));
+        }
+    }
+    pmt2=isVideo?priv->pmtVideo:priv->pmtAudio;
+
+    if(result==S_OK){
+        mp_msg(MSGT_TV,MSGL_V,"Format %s accepted. Copying my ourselves\n",isVideo?"video":"audio");
+        free_media_type(pmt2);
+        pPin->vt->ConnectionMediaType(pPin,pmt2);
+        pPin->vt->Release((IUnknown*)pPin);
+
+        mp_msg(MSGT_TV,MSGL_V,"Negotiated following %s format:\n",isVideo?"video":"audio");
+        print_pmt_info(pmt2);
+    }
+    return result;
+}
+
+
+/* 
+
+misc debug utilities 
+
+*/
+char* err2str(HRESULT err){
+    switch(err){
+        case 0x8004025f: return "VFW_E_NOT_IN_GRAPH";
+        case E_POINTER: return "E_POINTER";
+        case E_FAIL: return "E_FAIL";
+        case E_OUTOFMEMORY: return "E_OUTOFMEMRY";
+        case E_NOTIMPL: return "E_NOTIMPL";
+	case E_INVALIDARG: return "E_INVALIDARG";
+        case S_OK: return "S_OK (no error)";
+    }
+    return "Unknown";
+}
+
+
+
+void showError(char* msg,char*step,HRESULT hr){
+    char buf[200];
+    snprintf(buf,200,"%s (step %s) Error: (0x%x) %s",msg,step,(unsigned int)hr,err2str(hr));
+    mp_msg(MSGT_TV,MSGL_ERR,"%s\n",buf);
+}
+void showSuccess(char* msg,char*step){
+    char buf[200];
+    snprintf(buf,200,"%s (step %s) Result success",msg,step);
+    mp_msg(MSGT_TV,MSGL_INFO,"%s\n",buf);
+}
+
+
+#define EXIT_IF_CONDITION(condition,msg,step,err) if(condition) {showError(msg,step,err); goto exit;}
+#define EXIT_IF_FAILURE_HR(hr,msg,step) EXIT_IF_CONDITION(FAILED(hr),msg,step,hr)
+
+// stub
+int chanlist2country(char* chanlist){
+  if (strcmp(chanlist,"us-bcast")==0) return 1;
+  if (strcmp(chanlist,"russia")==0) return 7;
+  if (strcmp(chanlist,"argentina")==0) return 54;
+  if (strcmp(chanlist,"japan-bcast")==0) return 81;
+  if (strcmp(chanlist,"china-bcast")==0) return 86;
+  if (strcmp(chanlist,"southafrica")==0) return 27;
+  if (strcmp(chanlist,"australia")==0) return 61;
+  if (strcmp(chanlist,"ireland")==0) return 353;
+  if (strcmp(chanlist,"france")==0) return 33;
+  if (strcmp(chanlist,"italy")==0) return 39;
+  if (strcmp(chanlist,"newzealand")==0) return 64;
+  if (strcmp(chanlist,"europe-east")==0) return 7; //directshow table uses eastern europe freq table for russia
+  if (strcmp(chanlist,"europe-west")==0) return 49; //directshow table uses western europe freq table for germany
+  return 1; //USA
+/*
+    { "us-cable",         ntsc_cable,        CHAN_COUNT(ntsc_cable)        },
+    { "us-cable-hrc",     ntsc_hrc,          CHAN_COUNT(ntsc_hrc)          },
+    { "japan-cable",      ntsc_cable_jp,     CHAN_COUNT(ntsc_cable_jp)     },
+*/
+}
+
+
+#if 1
+AM_MEDIA_TYPE* GetMediaType(int width,int height,int fmt){
+    AM_MEDIA_TYPE* pmt;
+    VIDEOINFOHEADER* Vhdr;
+    int index;
+    printf("%d %d\n",sizeof(VIDEOINFOHEADER),sizeof(BITMAPINFOHEADER));
+
+    pmt=(AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
+    if(!pmt) return NULL;
+    memset(pmt, 0, sizeof(AM_MEDIA_TYPE));
+
+    for(index=0;img_fmt_list[index].fmt;index++)
+        if(img_fmt_list[index].fmt==fmt) break;
+
+    Vhdr = (VIDEOINFOHEADER*)CoTaskMemAlloc(sizeof(VIDEOINFOHEADER)+img_fmt_list[index].tail);
+
+    if(!Vhdr) { 
+        free(pmt);
+        return NULL;
+    }
+    memset(Vhdr,0,sizeof(VIDEOINFOHEADER)+img_fmt_list[index].tail);
+
+    pmt->majortype=MEDIATYPE_Video;
+    pmt->subtype=*img_fmt_list[index].subtype;
+
+    if(img_fmt_list[index].nCompression && img_fmt_list[index].nCompression!=3)
+        pmt->bFixedSizeSamples = 0;
+    else
+        pmt->bFixedSizeSamples = 1;
+
+    Vhdr->bmiHeader.biBitCount=img_fmt_list[index].nBits;
+    Vhdr->bmiHeader.biCompression=img_fmt_list[index].nCompression;
+    Vhdr->bmiHeader.biPlanes=1;
+    Vhdr->bmiHeader.biWidth=width;
+    Vhdr->bmiHeader.biHeight=height;
+
+    if(!Vhdr->bmiHeader.biCompression==3)
+        Vhdr->bmiHeader.biSizeImage=abs((int)(2*Vhdr->bmiHeader.biWidth*Vhdr->bmiHeader.biHeight));
+    else if (!Vhdr->bmiHeader.biCompression) 
+        Vhdr->bmiHeader.biSizeImage = labs(Vhdr->bmiHeader.biWidth * Vhdr->bmiHeader.biHeight) * ((Vhdr->bmiHeader.biBitCount + 7) / 8);        
+    else
+        Vhdr->bmiHeader.biSizeImage=labs(Vhdr->bmiHeader.biBitCount* Vhdr->bmiHeader.biWidth*Vhdr->bmiHeader.biHeight)>>3;
+
+    if (Vhdr->bmiHeader.biCompression!= 0 && Vhdr->bmiHeader.biCompression!= 3 && Vhdr->bmiHeader.biHeight > 0)
+        Vhdr->bmiHeader.biHeight *= -1; // YUV formats uses should have height < 0
+
+    Vhdr->bmiHeader.biSize=sizeof(BITMAPINFOHEADER)+img_fmt_list[index].tail;
+
+    pmt->formattype = FORMAT_VideoInfo;
+    pmt->cbFormat = Vhdr->bmiHeader.biSize;
+//    pmt->cbFormat = sizeof(VIDEOINFOHEADER)+img_fmt_list[index].tail;
+//    pmt->pbFormat = (char*)Vhdr; 
+    pmt->cbFormat = 0;
+    pmt->pbFormat = NULL; 
+    pmt->lSampleSize = Vhdr->bmiHeader.biSizeImage;
+
+    return pmt;
+}
+
+#endif
+HRESULT SetVCrossbar(ICaptureGraphBuilder2* pBuilder,IBaseFilter* pBaseFilter)
+{
+  HRESULT hr;
+  long lOutPinCount,lInPinCount;
+  long lOutVideoPinIndex=-1, lInVideoPinIndex;
+  long lPhisicalPinInfo,lReleatedPin;
+  IAMCrossbar *pCrossbar=NULL;
+
+  do {
+
+    hr = pBuilder->vt->FindInterface(pBuilder,&MY_PIN_CATEGORY,&MEDIATYPE_Video,pBaseFilter, &IID_IAMCrossbar, (void **)&pCrossbar);
+
+    if (FAILED(hr)) break;
+
+    //???????? ????????? ???? ???????????
+    pCrossbar->vt->get_PinCounts(pCrossbar,&lOutPinCount,&lInPinCount);
+
+    for (lOutVideoPinIndex=0; lOutVideoPinIndex<lOutPinCount; lOutVideoPinIndex++) {
+      pCrossbar->vt->get_CrossbarPinInfo(pCrossbar,0,lOutVideoPinIndex,&lReleatedPin,&lPhisicalPinInfo);
+      if (lPhisicalPinInfo==PhysConn_Video_VideoDecoder) {
+        //????? ????? ????? ???????????
+        for(lInVideoPinIndex=0; lInVideoPinIndex<lInPinCount; lInVideoPinIndex++) {
+          pCrossbar->vt->get_CrossbarPinInfo(pCrossbar,-1,lInVideoPinIndex,&lReleatedPin,&lPhisicalPinInfo);
+          if (lPhisicalPinInfo==PhysConn_Video_Tuner) {
+            //????? ????????? ???? ????? ???????
+            hr=pCrossbar->vt->Route(pCrossbar,lOutVideoPinIndex,lInVideoPinIndex);//???????????...
+            break;
+          }
+        }
+        break;
+      }
+    }
+  } while (0);
+  if(pCrossbar) pCrossbar->vt->Release((IUnknown*)pCrossbar);
+  return hr;
+}
+
+#if 1
+int setFreq(priv_t* priv,long nFreq){
+    HRESULT hr;
+    int i;
+
+    if(!priv->pTVTuner) return TVI_CONTROL_FALSE;
+
+    nFreq=1000*nFreq/16;
+    for(i=0;i<chanlists[priv->tvh->chanlist].count;i++){
+        if (nFreq==chanlists[priv->tvh->chanlist].list[i].freq)
+            break;
+    }
+    if (i==chanlists[priv->tvh->chanlist].count){
+        showError("Channel not found","setFreq",E_FAIL);
+        return TVI_CONTROL_FALSE;
+    }
+    mp_msg(MSGT_TV,MSGL_ERR,"Setting channel: %d\n",i+1);
+    hr=priv->pTVTuner->vt->put_Channel(priv->pTVTuner,i+1,AMTUNER_SUBCHAN_DEFAULT,AMTUNER_SUBCHAN_DEFAULT);
+    if(FAILED(hr)){
+        showError("Cannot change freq","setFreq",hr);
+        return TVI_CONTROL_FALSE;
+    }
+    return TVI_CONTROL_TRUE;
+}
+#else
+#define INSTANCEDATA_OF_PROPERTY_PTR(x) (((KSPROPERTY*)(x)) + 1)
+#define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY))
+
+HRESULT SetFrequency(IAMTVTuner* m_pTVTuner,long Freq)
+{ 
+    HRESULT hr;
+    DWORD dwSupported=0;  
+    KSPROPERTY_TUNER_MODE_CAPS_S ModeCaps;
+    KSPROPERTY_TUNER_FREQUENCY_S Frequency;
+    IKsPropertySet* m_pKSProp;
+
+    // Query the IKsPropertySet on your Device TV Tuner Filter.
+    // m_pTvtuner is IBaseFilter Pointer of your TV Tuner Filter.   
+
+    hr = m_pTVTuner->vt->QueryInterface((IUnknown*)m_pTVTuner,&IID_IKsPropertySet, (void**)&m_pKSProp); 
+    if (FAILED(hr)){
+        mp_msg(MSGT_TV,MSGL_ERR,"Set freq QueryInterface failure\n");
+        return E_FAIL;
+}
+    memset(&ModeCaps,0,sizeof(KSPROPERTY_TUNER_MODE_CAPS_S));
+    memset(&Frequency,0,sizeof(KSPROPERTY_TUNER_FREQUENCY_S));
+    ModeCaps.Mode = AMTUNER_MODE_TV; 
+
+    // Check either the Property is supported or not by the Tuner drivers 
+
+    hr = m_pKSProp->vt->QuerySupported(m_pKSProp,&PROPSETID_TUNER, KSPROPERTY_TUNER_MODE_CAPS,&dwSupported);
+    if(SUCCEEDED(hr) && dwSupported&KSPROPERTY_SUPPORT_GET)
+    {
+        DWORD cbBytes=0;
+        hr = m_pKSProp->vt->Get(m_pKSProp,&PROPSETID_TUNER,KSPROPERTY_TUNER_MODE_CAPS,
+            INSTANCEDATA_OF_PROPERTY_PTR(&ModeCaps),
+            INSTANCEDATA_OF_PROPERTY_SIZE(ModeCaps),
+            &ModeCaps,
+            sizeof(ModeCaps),
+            &cbBytes);  
+    }
+    else{
+        mp_msg(MSGT_TV,MSGL_ERR,"Set freq QuerySupported failure\n");
+        return E_FAIL; 
+}
+    Frequency.Frequency=Freq;
+    if(ModeCaps.Strategy==KS_TUNER_STRATEGY_DRIVER_TUNES)
+        Frequency.TuningFlags=KS_TUNER_TUNING_FINE;
+    else
+        Frequency.TuningFlags=KS_TUNER_TUNING_EXACT;
+
+    // Here the real magic starts
+
+    if(Freq>=ModeCaps.MinFrequency && Freq<=ModeCaps.MaxFrequency)
+    {
+        hr = m_pKSProp->vt->Set(m_pKSProp,&PROPSETID_TUNER,
+            KSPROPERTY_TUNER_FREQUENCY,
+            INSTANCEDATA_OF_PROPERTY_PTR(&Frequency),
+            INSTANCEDATA_OF_PROPERTY_SIZE(Frequency),
+            &Frequency,
+            sizeof(Frequency));
+        if(FAILED(hr)){
+        mp_msg(MSGT_TV,MSGL_ERR,"Set freq Set failure: %s (0x%x) %d\n\n",err2str(hr),hr,INSTANCEDATA_OF_PROPERTY_SIZE(Frequency) );
+            return E_FAIL;  }
+    }
+    else{
+        mp_msg(MSGT_TV,MSGL_ERR,"Set freq MinMax failure %ld (%ld,%ld)\n",Freq,ModeCaps.MinFrequency ,ModeCaps.MaxFrequency);
+        return E_FAIL;
+}
+    return S_OK;
+}
+
+int setFreq(priv_t* priv,long nFreq){
+    HRESULT hr;
+    IUnknown* pUnk;
+
+
+    hr=SetFrequency(priv->pTVTuner,1000000*nFreq/16);
+    if(FAILED(hr)){
+        mp_msg(MSGT_TV,MSGL_ERR,"Set freq failure\n");
+        return TVI_CONTROL_FALSE;
+    }
+    return TVI_CONTROL_TRUE;
+}
+
+#endif
+
+/*====== REVIEWED CODE BEGIN ============================*/
+
+/*
+*---------------------------------------------------------------------------------------
+*
+*  Grabbers
+*
+*---------------------------------------------------------------------------------------
+*/
+/*
+*---------------------------------------------------------------------------------------
+*
+*  Methods, called only from this file
+*
+*---------------------------------------------------------------------------------------
+*/
+AM_MEDIA_TYPE* create_audio_media_type(int samplerate,int bits,int channels){
+    WAVEFORMATEX* pWF;
+    AM_MEDIA_TYPE* pmt;
+
+    pmt=(AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
+    if(!pmt){
+        CoTaskMemFree(pWF);
+        return NULL;
+    }
+
+    memset(pmt, 0, sizeof(AM_MEDIA_TYPE));
+
+    pmt->majortype=MEDIATYPE_Audio;
+    pmt->subtype=MEDIASUBTYPE_PCM;
+    pmt->formattype=FORMAT_WaveFormatEx;
+    pmt->bFixedSizeSamples=1;
+    pmt->bTemporalCompression=0;
+    pmt->pUnk = NULL;
+    pmt->lSampleSize=channels * bits /8;
+    pmt->cbFormat=0;
+    pmt->pbFormat=NULL;
+    return pmt;
+}
+/*****************************************************************
+ * \brief prints filter name and it pins
+ * \parameter pFilter - IBaseFilter to get data from
+ * \return S_OK if success, error code otherwise
+ * 
+ */
+HRESULT show_filter_info(IBaseFilter *pFilter){
+    char tmp[200];
+    FILTER_INFO fi;
+    IEnumPins *pEnum = 0;
+    IPin *pPin = 0;
+    PIN_DIRECTION ThisPinDir;
+    PIN_INFO pi;
+    HRESULT hr;
+
+    memset(&fi,0,sizeof(fi));
+    memset(tmp,0,200);
+
+    pFilter->vt->QueryFilterInfo(pFilter,&fi);
+    if(fi.pGraph) fi.pGraph->vt->Release((IUnknown*)fi.pGraph);
+    wtoa(fi.achName,tmp,200);
+    mp_msg(MSGT_TV,MSGL_V,"tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p\n",pFilter,tmp,fi.pGraph);
+    mp_msg(MSGT_TV,MSGL_V,"tvi_dshow: BaseFilter (%p) pins:",pFilter);
+    hr = pFilter->vt->EnumPins(pFilter,&pEnum);
+    if (FAILED(hr))  return hr;
+    while (pEnum->vt->Next(pEnum,1, &pPin, NULL) == S_OK)
+    {
+        memset(&pi,0,sizeof(pi));
+        memset(tmp,0,200);
+        pPin->vt->QueryDirection((IUnknown*)pPin,&ThisPinDir);
+        pPin->vt->QueryPinInfo(pPin,&pi);
+        wtoa(pi.achName,tmp,200);
+        pi.pFilter->vt->Release((IUnknown*)pi.pFilter);
+        mp_msg(MSGT_TV,MSGL_V,"%p (%s,%s);",pPin,ThisPinDir==PINDIR_INPUT?"in":"out",tmp);
+        pPin->vt->Release((IUnknown*)pPin); 
+    }
+    mp_msg(MSGT_TV,MSGL_V,"\n");
+    pEnum->vt->Release((IUnknown*)pEnum);
+    return S_OK;
+}
+
+/*****************************************************************
+ * \brief gets device's frendly in ANSI encoding
+ * \parameter priv driver's private data structure 
+ * \parameter lFreq - pointer to long int to store frequency to
+ * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise
+ * 
+ * TODO: replace parameter from V$L style frequency to Hz
+ */
+int get_frequency(priv_t* priv,long* lFreq){
+    long nChannel;
+    if(!priv->pTVTuner) return TVI_CONTROL_FALSE;
+    if(FAILED(priv->pTVTuner->vt->get_Channel(priv->pTVTuner,&nChannel,NULL,NULL)))
+        return TVI_CONTROL_FALSE;
+    if (nChannel>chanlists[priv->tvh->chanlist].count || nChannel<0)
+        return TVI_CONTROL_FALSE;
+
+    *lFreq=chanlists[priv->tvh->chanlist].list[nChannel].freq*16/1000;
+
+    return TVI_CONTROL_TRUE;
+}
+
+/*****************************************************************
+ * \brief gets device's frendly in ANSI encoding
+ * \parameter pM IMoniker interface, got in enumeration process
+ * \parameter category device category 
+ * \return IBaseFilter interface for capture device with given index
+ * 
+ * TODO: replace Moniker with some device interface
+ */
+void get_device_name(IMoniker* pM,char* pBuf,int nLen){
+    HRESULT hr;
+    VARIANT var;
+    IPropertyBag* pPropBag;
+    hr = pM->vt->BindToStorage(pM,0, 0, &IID_IPropertyBag, (void**)(&pPropBag));
+    if (FAILED(hr)) {
+        mp_msg(MSGT_TV,MSGL_ERR,"Call to BindToStorage failed\n");
+        return ;
+    }
+    var.vt=VT_BSTR;
+    hr = pPropBag->vt->Read(pPropBag,L"Description", (LPVARIANT)&var, NULL);
+    if (FAILED(hr))
+    {
+        hr = pPropBag->vt->Read(pPropBag,L"FriendlyName", (LPVARIANT)&var, NULL);
+    }
+    pPropBag->vt->Release((IUnknown*)pPropBag);
+    if (SUCCEEDED(hr))
+    {
+        wtoa(var.bstrVal,pBuf,nLen);
+    }
+}
+
+/*****************************************************************
+ * \brief find capture device at given index
+ * \parameter index device index to search for
+ * \parameter 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
+ */
+#define MSGSIZE_MAX 3072
+IBaseFilter* find_capture_device(int index,REFCLSID category){
+    IBaseFilter* pBaseFilter=NULL;
+    ICreateDevEnum *pDevEnum=NULL;
+    IEnumMoniker   *pClassEnum=NULL;
+    IMoniker *pM;
+    HRESULT hr;
+    ULONG cFetched;
+    int i;
+    char tmp[MSGSIZE_MAX];
+    hr = CoCreateInstance((GUID*)&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, &IID_ICreateDevEnum, (void**)&pDevEnum);
+    if (FAILED(hr)){
+        mp_msg(MSGT_TV,MSGL_ERR,"Unable to create device enumerator\n");
+        return NULL;
+    }
+
+    hr = pDevEnum->vt->CreateClassEnumerator(pDevEnum,category, &pClassEnum,0);
+    pDevEnum->vt->Release((IUnknown*)pDevEnum);
+    if (FAILED(hr)){
+        mp_msg(MSGT_TV,MSGL_ERR,"Unable to create class enumerator\n");
+        return NULL;
+    }
+
+    pClassEnum->vt->Reset(pClassEnum);
+    for(i=0; pClassEnum->vt->Next(pClassEnum,1, &pM, &cFetched)==S_OK;i++){ 
+        get_device_name(pM,tmp,MSGSIZE_MAX-1);
+        mp_msg(MSGT_TV,MSGL_V,"tvi_dshow: Device #%d: %s\n",i,tmp);
+        if(i==index){
+            mp_msg(MSGT_TV,MSGL_INFO,"tvi_dshow: Using device #%d: %s\n",index,tmp);
+            hr = pM->vt->BindToObject(pM,0, 0, &IID_IBaseFilter, (void**)&pBaseFilter);
+            if (FAILED(hr))
+                pBaseFilter=NULL;
+        }
+       pM->vt->Release((IUnknown*)pM);
+    }
+    if(!pBaseFilter){
+        mp_msg(MSGT_TV,MSGL_ERR,"tvi_dshow: Device #%d not found\n",index);
+    }
+    pClassEnum->vt->Release((IUnknown*)pClassEnum);
+
+    return pBaseFilter;
+
+}
+
+/*****************************************************************
+ * \brief print tuner capabilities
+ * \parameter pTuner IAMTVtuner interface for capture device
+ * 
+ * NOTE: currently only prints TV norms, supported by device
+ *
+ */
+void print_capabilities(IAMTVTuner* pTuner){
+    long lAvailableFormats;
+    HRESULT hr;
+    int i;
+    
+    if(!pTuner) return ;
+
+    mp_msg(MSGT_TV, MSGL_INFO, " supported norms:");
+    hr= pTuner->vt->get_AvailableTVFormats(pTuner,&lAvailableFormats);
+    if (FAILED(hr)) { tv_available_norms_count=0; return ;}
+
+    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_INFO, " %d = %s;", tv_available_norms_count, tv_norms[i].name);
+	    tv_available_norms_count++;
+	}
+    }
+    /* stub */
+    mp_msg(MSGT_TV, MSGL_INFO, "\n inputs:");
+    for(i=0;i<TV_INPUTS_COUNT;i++){
+        tv_available_inputs[tv_available_inputs_count]=i;
+        mp_msg(MSGT_TV, MSGL_INFO, " %d = %s;", tv_available_inputs_count, tv_inputs[i].name);
+	tv_available_inputs_count++;
+    }
+    mp_msg(MSGT_TV, MSGL_INFO, "\n");
+    
+}
+
+/*
+*---------------------------------------------------------------------------------------
+*
+*  Public methods
+*
+*---------------------------------------------------------------------------------------
+*/
+/*****************************************************************
+ * \brief fills given buffer with audio data (usually one block)
+ * \parameter priv driver's private data structure 
+ * \parameter buffer buffer to store data to
+ * \parameter 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;
+    long long pts;
+    int total_bytes=0;
+    do{
+        bytes=priv->pGrabber->FillBuffer(priv->pGrabber,buffer+total_bytes,len-total_bytes,0,&pts);       
+        mp_msg(MSGT_TV,MSGL_DBG3,"FillBuffer (audio) received %d bytes pts=%lld \n",bytes,pts);
+        total_bytes+=bytes; 
+    } while (total_bytes<len);
+    return (double)1e-7*pts; // need real timer
+}
+
+/*****************************************************************
+ * \brief returns audio frame size
+ * \parameter 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->pmtAudio || !priv->pmtAudio->pbFormat) return 1; 
+    
+    return ((WAVEFORMATEX*)(priv->pmtAudio->pbFormat))->nAvgBytesPerSec/100;
+}
+
+/*****************************************************************
+ * \brief fills given buffer with video data (usually one frame)
+ * \parameter priv driver's private data structure 
+ * \parameter buffer buffer to store data to
+ * \parameter 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;
+    long long pts;
+    if(!priv->pmtVideo){
+        memset(buffer,0,len);
+        return 1;
+    }
+    bytes=priv->pGrabber->FillBuffer(priv->pGrabber,buffer,len,1,&pts);
+    mp_msg(MSGT_TV,MSGL_DBG3,"FillBuffer (video) received %d pts=%lld bytes\n",bytes,pts);
+    return (double)1e-7*pts; // need real timer
+}
+
+/*****************************************************************
+ * \brief returns frame size
+ * \parameter 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);
+}
+
+/*****************************************************************
+ * \brief playback/capture real start
+ * \parameter 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(set_media_format(priv,priv->pmtAudio)!=S_OK) return (0);
+    if(set_media_format(priv,priv->pmtVideo)!=S_OK) return (0);
+    /*
+       Graph ready to capture. Starting graph.
+    */
+    hr = priv->pMediaControl->vt->Run(priv->pMediaControl);
+    if (FAILED(hr))
+    {
+        mp_msg(MSGT_TV,MSGL_ERR,"Unable to start graph (error: 0x%08x)!\n",hr);
+        priv->pMediaControl->vt->Stop(priv->pMediaControl);
+        return 0;
+    }
+
+    priv->state=1;
+ 
+    return(1);
+exit:	
+    return(0);
+}
+
+/*****************************************************************
+ * \brief driver initialization
+ * \parameter priv driver's private data structure 
+ * \return 1 if success, 0 - otherwise
+ *
+ */
+static int init(priv_t *priv)
+{
+    HRESULT hr;
+    int result=0;
+
+    CoInitialize(NULL);
+
+    hr=CoCreateInstance ((GUID*)&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **) &priv->pGraph);
+    EXIT_IF_FAILURE_HR(hr,"Directshow graph initialization failure","CoCreateInstance(CLSID_FilterGraph,IID_IGraphbuilder)");
+
+    hr=CoCreateInstance ((GUID*)&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, &IID_ICaptureGraphBuilder2, (void **) &priv->pBuilder);
+    EXIT_IF_FAILURE_HR(hr,"Directshow graph initialization failure","CaptureGraphBuilder");
+
+
+    hr=priv->pBuilder->vt->SetFiltergraph(priv->pBuilder,priv->pGraph);
+    EXIT_IF_FAILURE_HR(hr,"Directshow graph initialization failure","SetFiltergraph");
+
+    priv->pBaseFilter=find_capture_device(priv->dev_index,&CLSID_VideoInputDeviceCategory);
+    EXIT_IF_CONDITION(!priv->pBaseFilter,"Unable to find capture device","find_capture_device",E_POINTER);
+
+    mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: BaseFilter found (%p)\n",priv->pBaseFilter);
+
+    hr=priv->pGraph->vt->AddFilter(priv->pGraph,priv->pBaseFilter, NULL);
+    EXIT_IF_FAILURE_HR(hr,"Unable to add capture device to Directshow graph","AddFilter(pBaseFilter");
+
+    show_filter_info(priv->pBaseFilter);
+
+#if 0
+    hr=SetVCrossbar(priv->pBuilder,priv->pBaseFilter);
+    EXIT_IF_FAILURE_HR(hr,"Unable to set crossbar","");
+#endif
+#if 0
+    mp_msg(MSGT_TV,MSGL_V,"==== Video types ====\n");
+    display_device_media_types(priv,&MEDIATYPE_Video);
+    mp_msg(MSGT_TV,MSGL_V,"==== Audio types ====\n");
+    display_device_media_types(priv,&MEDIATYPE_Audio);
+#endif
+
+    hr = priv->pGraph->vt->QueryInterface((IUnknown*)priv->pGraph,&IID_IMediaControl, (void **)&(priv->pMediaControl));
+    EXIT_IF_FAILURE_HR(hr,"Unable create instance of IMediaControl","IGraphBuilder_QueryInterface(IID_IMediaCOntrol");
+
+    hr=priv->pBuilder->vt->FindInterface(priv->pBuilder,&MY_PIN_CATEGORY,NULL,priv->pBaseFilter,&IID_IAMTVTuner, (void **)&(priv->pTVTuner));
+    EXIT_IF_FAILURE_HR(hr,"Unable to access tuner!failed","FindInterface(IID_IAMTVTuner)");
+
+    mp_msg(MSGT_TV,MSGL_DBG3,"Got pTVTuner (%p)\n",priv->pTVTuner);
+    // shows Tuner capabilities
+    print_capabilities(priv->pTVTuner); 
+
+    priv->pTVTuner->vt->put_CountryCode(priv->pTVTuner,chanlist2country(tv_param_chanlist));
+    priv->pTVTuner->vt->put_InputType(priv->pTVTuner,0,TunerInputAntenna);
+    hr=priv->pTVTuner->vt->put_Mode(priv->pTVTuner,AMTUNER_MODE_TV);
+
+    priv->pmtVideo=GetMediaType(priv->width,priv->height,priv->fcc);
+    priv->pmtAudio=create_audio_media_type(priv->samplerate,16,2);
+
+    priv->pGrabber=DS_MPGrabberCreate(priv->pmtVideo,priv->pmtAudio);
+    EXIT_IF_CONDITION(!priv->pGrabber,"Grabber create error","DS_MP_Grabber(create(pmt)",E_POINTER);
+
+    mp_msg(MSGT_TV,MSGL_DBG3,"DS_MPGrabber created (%p)\n",priv->pGrabber);
+
+    hr=priv->pGraph->vt->AddFilter(priv->pGraph,(IBaseFilter*)priv->pGrabber, NULL);
+    EXIT_IF_FAILURE_HR(hr,"Unable to add grabber to Directshow graph","AddFilter(gr)");
+
+    show_filter_info((IBaseFilter*)priv->pGrabber);
+
+    result=1;
+exit:
+    CoUninitialize(); 
+ 
+    if(!result) uninit(priv);
+ 
+    return result;
+}
+
+/*****************************************************************
+ * \brief driver uninitialization
+ * \parameter priv driver's private data structure 
+ * \return always 1
+ *
+ */
+static int uninit(priv_t *priv)
+{
+  
+    if (!priv) return (1);
+
+    //stop audio grabber thread
+
+    if(priv->pMediaControl){
+        priv->pMediaControl->vt->Stop(priv->pMediaControl);
+        priv->pMediaControl->vt->Release((IUnknown*)priv->pMediaControl);
+        priv->pMediaControl=NULL;
+    }
+
+    priv->state=0;
+
+    if(priv->pGrabber){
+        priv->pGrabber->vt->Release((IUnknown*)priv->pGrabber);
+        priv->pGrabber=NULL;
+    }
+    if(priv->pBaseFilter) {
+        priv->pBaseFilter->vt->Release((IUnknown*)priv->pBaseFilter); 
+        priv->pBaseFilter=NULL;
+    }
+    if(priv->pGraph) {
+//This is failed. I dont know why.
+//    IGraphBuilder_Release((IUnknown*)priv->pGraph);      
+        priv->pGraph=NULL;
+    }
+
+    if(priv->pBuilder){
+//  this is also failed!
+//    priv->pBuilder->vt->Release((IUnknown*)priv->pBuilder);    
+        priv->pBuilder=NULL;
+    }
+    if (priv->pmtVideo) 
+        delete_media_type(priv->pmtVideo);
+    if (priv->pmtAudio) 
+        delete_media_type(priv->pmtAudio);
+
+    return(1);
+}
+
+/*****************************************************************
+ * \brief driver pre-initialization
+ * \parameter 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
+ *
+ */
+tvi_handle_t *tvi_init_dshow(char *device)
+{
+    tvi_handle_t *h;
+    priv_t *priv;
+    int a,b;
+    
+    h = new_handle();
+    if (!h)
+        return(NULL);
+
+    priv = h->priv;
+    priv->tvh=h;
+
+    priv->pGraph=NULL;
+    priv->pBuilder=NULL;
+    priv->pTVTuner=NULL;
+    priv->pBaseFilter=NULL;
+    priv->pGrabber=NULL;
+    priv->pmtVideo=NULL;
+    priv->pmtAudio=NULL;
+    priv->pmtAudio=NULL;
+    priv->pmtVideo=NULL;
+    priv->dev_index=0;
+    priv->dev_pin=0;
+    priv->state=0;
+
+    priv->width=320;
+    priv->height=240;
+    priv->fcc=IMGFMT_YUY2;
+    priv->samplerate=44100;
+
+    if (tv_param_device){
+        if (sscanf(tv_param_device, "%d.%d", &a,&b)==2){
+            priv->dev_index=a;
+            priv->dev_pin=b;
+        }else if (sscanf(tv_param_device, "%d", &a)==1){
+            priv->dev_index=a;
+        }else{
+            mp_msg(MSGT_TV,MSGL_ERR,"Wrong device parameter: %s\n",tv_param_device);
+            free_handle(h);
+            return NULL;
+        }
+        if (priv->dev_index<0){
+            mp_msg(MSGT_TV,MSGL_ERR,"Wrong device index: %d\n",a);
+            free_handle(h);
+            return NULL;
+        }
+    }
+    return h;
+}
+
+/*****************************************************************
+ * \brief driver's ioctl handler
+ * \parameter priv driver's private data structure 
+ * \parameter cmd ioctl command
+ * \parameter arg ioct command's parameter
+ * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE if failure, TVI_CONTROL_UNKNOWN ifwhen unknowm cmd given
+ *
+ */
+static int control(priv_t *priv, int cmd, void *arg)
+{
+    switch(cmd)
+    {
+/* need rewrite */
+	case TVI_CONTROL_VID_SET_FORMAT:
+	{
+            if (priv->state) return TVI_CONTROL_FALSE;
+	    priv->fcc = *(int *)arg;
+            return TVI_CONTROL_TRUE;
+	}
+	case TVI_CONTROL_VID_GET_FORMAT:
+        {
+            if(priv->fcc){
+                *(int *)arg = priv->fcc;
+	        return(TVI_CONTROL_TRUE);
+            }else
+                return(TVI_CONTROL_FALSE);
+        }
+	case TVI_CONTROL_VID_SET_WIDTH:
+        {
+            if (priv->state) return TVI_CONTROL_FALSE;
+	    priv->width = *(int *)arg;
+	    return(TVI_CONTROL_FALSE); 
+        }
+	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_SET_HEIGHT:
+            if (priv->state) return TVI_CONTROL_FALSE;
+	    priv->height = *(int *)arg;
+	    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_WIDTH:
+	case TVI_CONTROL_VID_CHK_HEIGHT:
+	    return(TVI_CONTROL_TRUE);
+        case TVI_CONTROL_IS_AUDIO:
+            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;
+            return TVI_CONTROL_TRUE;
+        }
+        case TVI_CONTROL_AUD_GET_CHANNELS:
+        {
+            *(int *)arg = 2;
+            return TVI_CONTROL_TRUE;
+        }
+/* partually ready */
+       //currently i didn't find norm changing method
+	case TVI_CONTROL_TUN_SET_NORM:
+	    return(TVI_CONTROL_TRUE);
+/* ready */	    
+        case TVI_CONTROL_AUD_SET_SAMPLERATE:
+        {
+            int samplerate=*(int*)arg;
+            AM_MEDIA_TYPE* pmt;
+            HRESULT hr;
+
+            pmt=create_audio_media_type(samplerate,16,2);
+            hr=set_media_format(priv,pmt);
+            if(FAILED(hr)) return TVI_CONTROL_FALSE;
+            priv->samplerate=samplerate;
+            return TVI_CONTROL_TRUE;
+        }
+        case TVI_CONTROL_AUD_GET_SAMPLERATE:
+        {
+            if(!priv->samplerate) return TVI_CONTROL_FALSE;
+            *(int *)arg = priv->samplerate;
+            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_GET_NORM:
+	{
+	    long lAnalogFormat;
+	    int i;
+            if(!priv->pTVTuner) return TVI_CONTROL_FALSE;
+	    if (FAILED(priv->pTVTuner->vt->get_TVFormat(priv->pTVTuner,&lAnalogFormat)))
+	        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;
+		    return TVI_CONTROL_TRUE;
+	    }
+	    //currently i didn't find norm changing method
+	    return(TVI_CONTROL_FALSE);
+	}
+        case TVI_CONTROL_SPC_GET_NORMID:
+	{
+	    int i;
+	    for(i=0;i<tv_available_norms_count;i++){
+	        if (!strcasecmp(tv_norms[tv_available_norms[i]].name,(char *)arg))
+		    *(int *)arg = i;
+		    return TVI_CONTROL_TRUE;
+	    }
+	    return TVI_CONTROL_FALSE;
+	}
+	case TVI_CONTROL_TUN_GET_FREQ:
+	    return get_frequency(priv,(unsigned long*)arg);
+	case TVI_CONTROL_TUN_SET_FREQ:
+        {
+            int nFreq=*(unsigned long *)arg;
+	    return setFreq(priv,nFreq);
+        }
+    }
+    return(TVI_CONTROL_UNKNOWN);
+}
+
+/*====== REVIEWED CODE END ============================*/
Index: stream/tvi_dshow.h
===================================================================
--- stream/tvi_dshow.h	(revision 0)
+++ stream/tvi_dshow.h	(revision 0)
@@ -0,0 +1,547 @@
+#ifndef _H_TVI_DSHOW_H_
+#define _H_TVI_DSHOW_H_
+
+#include "loader/win32.h"
+#include "loader/dshow/guids.h"
+#include "loader/dshow/interfaces.h"
+
+#define GUID_DEFINED
+
+#include <basetyps.h>
+#include <winerror.h>
+
+STDAPI CoInitialize(PVOID);
+STDAPI_(void) CoUninitialize(void);
+
+extern const GUID CLSID_CaptureGraphBuilder;
+extern const GUID CLSID_CaptureGraphBuilder2;
+extern const GUID CLSID_FilterGraph;
+extern const GUID CLSID_SystemDeviceEnum;
+extern const GUID CLSID_VideoInputDeviceCategory;
+extern const GUID CLSID_AudioInputDeviceCategory;
+
+extern const GUID IID_IAMTVTuner;
+extern const GUID IID_IAMCrossbar;
+extern const GUID IID_ICaptureGraphBuilder;
+extern const GUID IID_ICaptureGraphBuilder2;
+extern const GUID IID_IFilterGraph;
+extern const GUID IID_ICreateDevEnum;
+extern const GUID IID_IPropertyBag;
+extern const GUID IID_IMediaControl;
+extern const GUID IID_IGraphBuilder;
+
+extern const GUID PIN_CATEGORY_CAPTURE;
+extern const GUID PIN_CATEGORY_PREVIEW;
+
+
+#ifndef BOOL
+#define BOOL unsigned char
+#define LPBOOL unsigned char*
+#endif
+
+
+#ifndef interface
+#define interface struct
+#endif
+
+#ifndef UINT
+#define UINT unsigned int
+#endif
+
+
+#ifndef ULONG
+#define ULONG unsigned long
+#endif
+
+#ifndef LONG
+#define LONG long
+#endif
+
+
+typedef LPCWSTR LPCOLESTR;
+typedef LPWSTR LPOLESTR;
+typedef WCHAR OLECHAR;
+typedef OLECHAR *BSTR;
+typedef LONG DISPID;
+typedef struct IUnknown* LPUNKNOWN;
+typedef struct IRecordInfo* LPRECORDINFO;
+typedef struct _IFileSinkFilter IFileSinkFilter;
+typedef struct _IAMCopyCaptureFileProgress IAMCopyCaptureFileProgress;
+
+#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 
+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;
+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 struct IDispatch* LPDISPATCH;
+typedef unsigned short VARTYPE;
+typedef short VARIANT_BOOL;
+typedef union tagCY {
+    struct {
+#ifdef WORDS_BIGENDIAN
+        LONG  Hi;
+        ULONG Lo;
+#else
+        ULONG Lo;
+        LONG  Hi;
+#endif
+    } DUMMYSTRUCTNAME;
+    LONGLONG int64;
+} CY;
+typedef struct tagDEC {
+  USHORT wReserved;
+  union {
+    struct {
+      BYTE scale;
+      BYTE sign;
+    } DUMMYSTRUCTNAME;
+    USHORT signscale;
+  } DUMMYUNIONNAME;
+  ULONG Hi32;
+  union {
+    struct {
+#ifdef WORDS_BIGENDIAN
+      ULONG Mid32;
+      ULONG Lo32;
+#else
+      ULONG Lo32;
+      ULONG Mid32;
+#endif
+    } DUMMYSTRUCTNAME1;
+    ULONGLONG Lo64;
+  } DUMMYUNIONNAME1;
+} DECIMAL;
+
+enum VARENUM {
+	VT_EMPTY,VT_NULL,VT_I2,VT_I4,VT_R4,VT_R8,VT_CY,VT_DATE,VT_BSTR,VT_DISPATCH,
+	VT_ERROR,VT_BOOL,VT_VARIANT,VT_UNKNOWN,VT_DECIMAL,VT_I1=16,VT_UI1,VT_UI2,VT_UI4,VT_I8,
+	VT_UI8,VT_INT,VT_UINT,VT_VOID,VT_HRESULT,VT_PTR,VT_SAFEARRAY,VT_CARRAY,VT_USERDEFINED,
+	VT_LPSTR,VT_LPWSTR,VT_RECORD=36,VT_FILETIME=64,VT_BLOB,VT_STREAM,VT_STORAGE,VT_STREAMED_OBJECT,
+	VT_STORED_OBJECT,VT_BLOB_OBJECT,VT_CF,VT_CLSID,VT_BSTR_BLOB=0xfff,VT_VECTOR=0x1000,
+	VT_ARRAY=0x2000,VT_BYREF=0x4000,VT_RESERVED=0x8000,VT_ILLEGAL= 0xffff,VT_ILLEGALMASKED=0xfff,
+	VT_TYPEMASK=0xfff
+};
+typedef struct tagSAFEARRAYBOUND {
+    ULONG cElements;
+    LONG lLbound;
+} SAFEARRAYBOUND, *LPSAFEARRAYBOUND;
+typedef struct tagSAFEARRAY {
+    USHORT cDims;
+    USHORT fFeatures;
+    ULONG cbElements;
+    ULONG cLocks;
+    PVOID pvData;
+    SAFEARRAYBOUND rgsabound[1];
+} SAFEARRAY;
+
+typedef SAFEARRAY *LPSAFEARRAY;
+
+
+typedef struct tagVARIANT VARIANT;
+typedef struct VARIANT* LPVARIANT;
+
+struct tagVARIANT {
+    union {
+        struct {
+            VARTYPE vt;
+            WORD wReserved1;
+            WORD wReserved2;
+            WORD wReserved3;
+            union {
+                signed char cVal;
+                USHORT uiVal;
+                ULONG ulVal;
+                INT intVal;
+                UINT uintVal;
+                BYTE bVal;
+                SHORT iVal;
+                LONG lVal;
+                FLOAT fltVal;
+                DOUBLE dblVal;
+                VARIANT_BOOL boolVal;
+                SCODE scode;
+                DATE date;
+                BSTR bstrVal;
+                CY cyVal;
+                LPUNKNOWN punkVal;
+                LPDISPATCH *pdispVal;
+                SAFEARRAY *parray;
+                LONGLONG llVal;
+                ULONGLONG ullVal;
+                signed char *pcVal;
+                USHORT *puiVal;
+                ULONG *pulVal;
+                INT *pintVal;
+                UINT *puintVal;
+                BYTE *pbVal;
+                SHORT *piVal;
+                LONG *plVal;
+                FLOAT *pfltVal;
+                DOUBLE *pdblVal;
+                VARIANT_BOOL *pboolVal;
+                SCODE *pscode;
+                DATE *pdate;
+                BSTR *pbstrVal;
+                VARIANT *pvarVal;
+                PVOID byref;
+                CY *pcyVal;
+                DECIMAL *pdecVal;
+                LPUNKNOWN *ppunkVal;
+                LPDISPATCH *ppdispVal;
+                SAFEARRAY **pparray;
+                LONGLONG *pllVal;
+                ULONGLONG *pullVal;
+                struct __tagBRECORD {
+                    PVOID pvRecord;
+                    LPRECORDINFO pRecInfo;
+                } ;
+            } ;
+        } ;
+        DECIMAL decVal;
+    } ;
+};
+
+typedef struct tagEXCEPINFO {
+	WORD wCode;
+	WORD wReserved;
+	BSTR bstrSource;
+	BSTR bstrDescription;
+	BSTR bstrHelpFile;
+	DWORD dwHelpContext;
+	PVOID pvReserved;
+	HRESULT(__stdcall * pfnDeferredFillIn)(struct tagEXCEPINFO*);
+	SCODE scode;
+} EXCEPINFO,*LPEXCEPINFO;
+
+typedef enum tagCLSCTX {
+	CLSCTX_INPROC_SERVER=1,CLSCTX_INPROC_HANDLER=2,CLSCTX_LOCAL_SERVER=4,
+	CLSCTX_INPROC_SERVER16=8,CLSCTX_REMOTE_SERVER=16
+} CLSCTX;
+typedef LONGLONG DWORDLONG;
+
+typedef long OAFilterState;
+
+typedef 
+enum tagAMTunerSubChannel
+    {	AMTUNER_SUBCHAN_NO_TUNE	= -2,
+	AMTUNER_SUBCHAN_DEFAULT	= -1
+    }	AMTunerSubChannel;
+
+
+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 AMTunerNotification* LPAMTUNERNOTIFICATION;
+typedef struct IEnumFilters* LPENUMFILTERS;
+typedef struct IFileSinkFilter* LPFILESINKFILTER;
+typedef struct IStream* LPSTREAM;
+typedef struct IBindCtx* LPBINDCTX;
+typedef struct IErrorLog* LPERRORLOG;
+typedef struct ITypeInfo* LPTYPEINFO;
+typedef struct IAMCopyCaptureFileProgress* LPAMCOPYCAPTUREFILEPROGRESS;
+typedef struct DISPPARAMS* LPDISPPARAMS;
+
+typedef struct _IAMTVTuner IAMTVTuner;
+typedef struct IAMTVTuner_vt
+{
+    INHERIT_IUNKNOWN();
+    HRESULT STDCALL ( *put_Channel)		(IAMTVTuner *, long,long,long) ;
+    HRESULT STDCALL ( *get_Channel)		(IAMTVTuner *, long*,long*,long*) ;
+    HRESULT STDCALL ( *ChannelMinMax)	(IAMTVTuner *, long*,long*) ;
+    HRESULT STDCALL ( *put_CountryCode)	(IAMTVTuner *, long) ;
+    HRESULT STDCALL ( *get_CountryCode)	(IAMTVTuner *, long*) ;
+    HRESULT STDCALL ( *put_TuningSpace)	(IAMTVTuner *, long) ;
+    HRESULT STDCALL ( *get_TuningSpace)	(IAMTVTuner *, long*) ;
+    HRESULT STDCALL ( *Logon)		(IAMTVTuner *, HANDLE) ;
+    HRESULT STDCALL ( *Logout)		(IAMTVTuner *) ;
+    HRESULT STDCALL ( *SignalPresen)		(IAMTVTuner *, long*) ;
+    HRESULT STDCALL ( *put_Mode)		(IAMTVTuner *, AMTunerModeType) ;
+    HRESULT STDCALL ( *get_Mode)		(IAMTVTuner *, AMTunerModeType*) ;
+    HRESULT STDCALL ( *GetAvailableModes)	(IAMTVTuner *, long*) ;
+    HRESULT STDCALL ( *RegisterNotificationCallBack)(IAMTVTuner *, LPAMTUNERNOTIFICATION,long) ;
+    HRESULT STDCALL ( *UnRegisterNotificationCallBack)(IAMTVTuner *, LPAMTUNERNOTIFICATION) ;
+    HRESULT STDCALL ( *get_AvailableTVFormats)(IAMTVTuner *, long*) ;
+    HRESULT STDCALL ( *get_TVFormat)		(IAMTVTuner *, long*) ;
+    HRESULT STDCALL ( *AutoTune)		(IAMTVTuner *, long,long*) ;
+    HRESULT STDCALL ( *StoreAutoTune)	(IAMTVTuner *) ;
+    HRESULT STDCALL ( *get_NumInputConnections)(IAMTVTuner *, long*) ;
+    HRESULT STDCALL ( *put_InputType)	(IAMTVTuner *, long,TunerInputType) ;
+    HRESULT STDCALL ( *get_InputType)	(IAMTVTuner *, long,TunerInputType*) ;
+    HRESULT STDCALL ( *put_ConnectInput)	(IAMTVTuner *, long) ;
+    HRESULT STDCALL ( *get_ConnectInput)	(IAMTVTuner *, long*) ;
+    HRESULT STDCALL ( *get_VideoFrequency)	(IAMTVTuner *, long*) ;
+    HRESULT STDCALL ( *get_AudioFrequency)	(IAMTVTuner *, long*) ;
+} IAMTVTuner_vt;
+struct _IAMTVTuner { struct IAMTVTuner_vt* vt; };
+typedef struct _IMediaControl IMediaControl;
+typedef struct IMediaControl_vt
+{
+    INHERIT_IUNKNOWN();
+	HRESULT STDCALL ( *GetTypeInfoCount )(IMediaControl *, UINT *);
+	HRESULT STDCALL ( *GetTypeInfo )(IMediaControl *, UINT,LCID,LPTYPEINFO*);
+	HRESULT STDCALL ( *GetIDsOfNames )(IMediaControl *, REFIID,LPOLESTR *,UINT,LCID,DISPID *);
+	HRESULT STDCALL ( *Invoke )(IMediaControl *, DISPID ,REFIID ,LCID ,WORD ,LPDISPPARAMS ,VARIANT *,EXCEPINFO *,UINT *);
+	HRESULT STDCALL ( *Run )(IMediaControl *) ;
+	HRESULT STDCALL ( *Pause )(IMediaControl *) ;
+	HRESULT STDCALL ( *Stop )(IMediaControl *) ;
+	HRESULT STDCALL ( *GetState )(IMediaControl *, LONG,OAFilterState *);
+	HRESULT STDCALL ( *RenderFile )(IMediaControl *, BSTR);
+	HRESULT STDCALL ( *AddSourceFilter )(IMediaControl *, BSTR,LPDISPATCH *);
+	HRESULT STDCALL ( *get_FilterCollection )(IMediaControl *, LPDISPATCH*);
+	HRESULT STDCALL ( *get_RegFilterCollection )(IMediaControl *, LPDISPATCH*);
+	HRESULT STDCALL ( *StopWhenReady )(IMediaControl *) ;
+} IMediaControl_vt;
+struct _IMediaControl {struct IMediaControl_vt* vt;};
+
+typedef struct _IGraphBuilder IGraphBuilder;
+typedef struct IGraphBuilder_vt
+{
+    INHERIT_IUNKNOWN();
+	HRESULT STDCALL ( *AddFilter)(IGraphBuilder*, IBaseFilter*,LPCWSTR) ;
+	HRESULT STDCALL ( *RemoveFilter)(IGraphBuilder*, IBaseFilter*) ;
+	HRESULT STDCALL ( *EnumFilters)(IGraphBuilder*, LPENUMFILTERS*) ;
+	HRESULT STDCALL ( *FindFilterByName)(IGraphBuilder*, LPCWSTR,IBaseFilter**) ;
+	HRESULT STDCALL ( *ConnectDirect)(IGraphBuilder*, IPin*,IPin*,const AM_MEDIA_TYPE*) ;
+	HRESULT STDCALL ( *Reconnect)(IGraphBuilder*, IPin*) ;
+	HRESULT STDCALL ( *Disconnect)(IGraphBuilder*, IPin*) ;
+	HRESULT STDCALL ( *SetDefaultSyncSource)(IGraphBuilder*) ;
+	HRESULT STDCALL ( *Connect)(IGraphBuilder*, IPin* ,IPin*) ;
+	HRESULT STDCALL ( *Render)(IGraphBuilder*, IPin*) ;
+	HRESULT STDCALL ( *RenderFile)(IGraphBuilder*, LPCWSTR,LPCWSTR) ;
+	HRESULT STDCALL ( *AddSourceFilter)(IGraphBuilder*, LPCWSTR,LPCWSTR,IBaseFilter**) ;
+	HRESULT STDCALL ( *SetLogFile)(IGraphBuilder*, DWORD_PTR) ;
+	HRESULT STDCALL ( *Abort)(IGraphBuilder*) ;
+	HRESULT STDCALL ( *ShouldOperationContinue)(IGraphBuilder*) ;
+} IGraphBuilder_vt;
+struct _IGraphBuilder { struct IGraphBuilder_vt* vt; };
+
+typedef struct _ICaptureGraphBuilder ICaptureGraphBuilder;
+typedef struct ICaptureGraphBuilder_vt
+{
+    INHERIT_IUNKNOWN();
+	HRESULT STDCALL ( *SetFiltergraph)(ICaptureGraphBuilder*, IGraphBuilder*) ;
+	HRESULT STDCALL ( *GetFiltergraph)(ICaptureGraphBuilder*, IGraphBuilder**) ;
+	HRESULT STDCALL ( *SetOutputFileName)(ICaptureGraphBuilder*, const GUID*,LPCOLESTR,IBaseFilter**,LPFILESINKFILTER*) ;
+	HRESULT STDCALL ( *FindInterface)(ICaptureGraphBuilder*, const GUID*,IBaseFilter*,REFIID,void** ) ;
+	HRESULT STDCALL ( *RenderStream)(ICaptureGraphBuilder*, const GUID*,LPUNKNOWN,IBaseFilter*,IBaseFilter*) ;
+	HRESULT STDCALL ( *ControlStream)(ICaptureGraphBuilder*, const GUID*,IBaseFilter*,REFERENCE_TIME*,REFERENCE_TIME*,WORD,WORD) ;
+	HRESULT STDCALL ( *AllocCapFile)(ICaptureGraphBuilder*, LPCOLESTR,DWORDLONG) ;
+	HRESULT STDCALL ( *CopyCaptureFile)(ICaptureGraphBuilder*, LPOLESTR,LPOLESTR,int,LPAMCOPYCAPTUREFILEPROGRESS) ;
+} ICaptureGraphBuilder_vt;
+struct _ICaptureGraphBuilder {struct ICaptureGraphBuilder_vt* vt;};
+
+typedef struct _ICaptureGraphBuilder2 ICaptureGraphBuilder2;
+typedef struct ICaptureGraphBuilder2_vt 
+{
+    INHERIT_IUNKNOWN();
+    HRESULT STDCALL ( *SetFiltergraph)(ICaptureGraphBuilder2* This,IGraphBuilder* pfg);
+    HRESULT STDCALL ( *GetFiltergraph)(ICaptureGraphBuilder2* This,IGraphBuilder** ppfg);
+    HRESULT STDCALL ( *SetOutputFileName)(ICaptureGraphBuilder2* This,const GUID* pType,LPCOLESTR lpstrFile,IBaseFilter** ppf,IFileSinkFilter** ppSink);
+    HRESULT STDCALL ( *FindInterface)(ICaptureGraphBuilder2* This,const GUID* pCategory,const GUID* pType,IBaseFilter* pf,REFIID riid,void** ppint);
+    HRESULT STDCALL ( *RenderStream)(ICaptureGraphBuilder2* This,const GUID* pCategory,const GUID* pType,IUnknown* pSource,IBaseFilter* pfCompressor,IBaseFilter* pfRenderer);
+    HRESULT STDCALL ( *ControlStream)(ICaptureGraphBuilder2* This,const GUID* pCategory,const GUID* pType,IBaseFilter* pFilter,REFERENCE_TIME* pstart,REFERENCE_TIME* pstop,WORD wStartCookie,WORD wStopCookie);
+    HRESULT STDCALL ( *AllocCapFile)(ICaptureGraphBuilder2* This,LPCOLESTR lpstr,DWORDLONG dwlSize);
+    HRESULT STDCALL ( *CopyCaptureFile)(ICaptureGraphBuilder2* This,LPOLESTR lpwstrOld,LPOLESTR lpwstrNew,int fAllowEscAbort,IAMCopyCaptureFileProgress* pCallback);
+    HRESULT STDCALL ( *FindPin)(ICaptureGraphBuilder2* This,IUnknown* pSource,PIN_DIRECTION pindir,const GUID* pCategory,const GUID* pType,BOOL fUnconnected,int num,IPin** ppPin);
+} ICaptureGraphBuilder2_vt;
+struct _ICaptureGraphBuilder2 {struct ICaptureGraphBuilder2_vt* vt;};
+
+typedef struct _IMoniker IMoniker;
+typedef struct _IEnumMoniker IEnumMoniker;
+
+typedef struct IMoniker_vt
+{
+    INHERIT_IUNKNOWN();
+	HRESULT STDCALL ( *GetClassID)(IMoniker*, LPCLSID) ;
+	HRESULT STDCALL ( *IsDirty)(IMoniker*) ;
+	HRESULT STDCALL ( *Load)(IMoniker*, LPSTREAM) ;
+	HRESULT STDCALL ( *Save)(IMoniker*, LPSTREAM,BOOL) ;
+	HRESULT STDCALL ( *GetSizeMax)(IMoniker*, PULARGE_INTEGER) ;
+	HRESULT STDCALL ( *BindToObject)(IMoniker*, LPBINDCTX,IMoniker*,REFIID,PVOID*) ;
+	HRESULT STDCALL ( *BindToStorage)(IMoniker*, LPBINDCTX,IMoniker*,REFIID,PVOID*) ;
+	HRESULT STDCALL ( *Reduce)(IMoniker*, LPBINDCTX,DWORD,IMoniker**,IMoniker**) ;
+	HRESULT STDCALL ( *ComposeWith)(IMoniker*, IMoniker*,BOOL,IMoniker**) ;
+	HRESULT STDCALL ( *Enum)(IMoniker*, BOOL,IEnumMoniker**) ;
+	HRESULT STDCALL ( *IsEqual)(IMoniker*, IMoniker*) ;
+	HRESULT STDCALL ( *Hash)(IMoniker*, PDWORD) ;
+	HRESULT STDCALL ( *IsRunning)(IMoniker*, LPBINDCTX,IMoniker*,IMoniker*) ;
+	HRESULT STDCALL ( *GetTimeOfLastChange)(IMoniker*, LPBINDCTX,IMoniker*,LPFILETIME) ;
+	HRESULT STDCALL ( *Inverse)(IMoniker*, IMoniker**) ;
+	HRESULT STDCALL ( *CommonPrefixWith)(IMoniker*, IMoniker*,IMoniker**) ;
+	HRESULT STDCALL ( *RelativePathTo)(IMoniker*, IMoniker*,IMoniker**) ;
+	HRESULT STDCALL ( *GetDisplayName)(IMoniker*, LPBINDCTX,IMoniker*,LPOLESTR*) ;
+	HRESULT STDCALL ( *ParseDisplayName)(IMoniker*, LPBINDCTX,IMoniker*,LPOLESTR,ULONG*,IMoniker**) ;
+	HRESULT STDCALL ( *IsSystemMoniker)(IMoniker*, PDWORD) ;
+} IMoniker_vt;
+struct _IMoniker {struct IMoniker_vt* vt;};
+
+typedef struct IEnumMoniker_vt
+{
+    INHERIT_IUNKNOWN();
+	HRESULT STDCALL ( *Next)(IEnumMoniker*,ULONG,IMoniker**,ULONG*) ;
+	HRESULT STDCALL ( *Skip)(IEnumMoniker*,ULONG) ;
+	HRESULT STDCALL ( *Reset)(IEnumMoniker*) ;
+	HRESULT STDCALL ( *Clone)(IEnumMoniker*,IEnumMoniker**) ;
+} IEnumMoniker_vt;
+struct _IEnumMoniker {struct IEnumMoniker_vt* vt;};
+
+typedef struct _ICreateDevEnum ICreateDevEnum;
+typedef struct ICreateDevEnum_vt
+{
+    INHERIT_IUNKNOWN();
+	HRESULT STDCALL ( *CreateClassEnumerator)(ICreateDevEnum*,REFCLSID,IEnumMoniker**,DWORD) ;
+} ICreateDevEnum_vt;
+struct _ICreateDevEnum {struct ICreateDevEnum_vt *vt;};
+
+typedef struct _IAMCrossbar IAMCrossbar;
+typedef struct IAMCrossbar_vt
+{
+    INHERIT_IUNKNOWN();
+	HRESULT STDCALL ( *get_PinCounts )( IAMCrossbar  * This,long  *OutputPinCount,long  *InputPinCount);
+	HRESULT STDCALL ( *CanRoute )( IAMCrossbar  * This,long OutputPinIndex,long InputPinIndex);
+	HRESULT STDCALL ( *Route )( IAMCrossbar  * This,long OutputPinIndex,long InputPinIndex);
+	HRESULT STDCALL ( *get_IsRoutedTo )( IAMCrossbar  * This,long OutputPinIndex,long  *InputPinIndex);       
+	HRESULT STDCALL ( *get_CrossbarPinInfo )( IAMCrossbar  * This,BOOL IsInputPin,long PinIndex,long  *PinIndexRelated,long  *PhysicalType);
+} IAMCrossbar_vt;
+struct _IAMCrossbar {struct  IAMCrossbar_vt* vt;};
+
+typedef struct _IPropertyBag IPropertyBag;
+typedef struct IPropertyBag_vt
+{
+    INHERIT_IUNKNOWN();
+	HRESULT STDCALL ( *Read)(IPropertyBag*, LPCOLESTR,LPVARIANT,LPERRORLOG) ;
+	HRESULT STDCALL ( *Write)(IPropertyBag*, LPCOLESTR,LPVARIANT) ;
+} IPropertyBag_vt;
+struct _IPropertyBag {struct IPropertyBag_vt* vt;};
+
+/*************************************************************************************/
+#define KSPROPERTY_SUPPORT_GET  1
+#define KSPROPERTY_SUPPORT_SET  2
+typedef struct {
+  GUID  Set;
+  ULONG  Id;
+  ULONG  Flags;
+} KSIDENTIFIER;
+DEFINE_GUID(PROPSETID_TUNER,			0x6a2e0605, 0x28e4, 0x11d0, 0xa1, 0x8c, 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56);
+
+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 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 struct _IKsPropertySet IKsPropertySet;
+typedef struct IKsPropertySet_vt {
+    INHERIT_IUNKNOWN();
+    HRESULT (STDMETHODCALLTYPE *Set)(IKsPropertySet* This,REFGUID guidPropSet,DWORD dwPropID,LPVOID pInstanceData,DWORD cbInstanceData,LPVOID pPropData,DWORD cbPropData);
+    HRESULT (STDMETHODCALLTYPE *Get)(IKsPropertySet* This,REFGUID guidPropSet,DWORD dwPropID,LPVOID pInstanceData,DWORD cbInstanceData,LPVOID pPropData,DWORD cbPropData,DWORD* pcbReturned);
+    HRESULT (STDMETHODCALLTYPE *QuerySupported)(IKsPropertySet* This,REFGUID guidPropSet,DWORD dwPropID,DWORD* pTypeSupport);
+} IKsPropertySet_vt;
+struct _IKsPropertySet {struct IKsPropertySet_vt* vt;};
+
+
+#endif //_H_TVI_DSHOW_H_


More information about the MPlayer-dev-eng mailing list