Page 1 of 1

Directshow Filter Selection

Posted: Mon Feb 28, 2005 7:10 am
by normen
Hi,
I am a newbie, so please excuse any unqualified remarks.
I am trying to write a little movie player and want it to play ANY media file imaginable. After installing Real Alternative, I was hoping that I could play rm files, but there seems to be a bit of a problem. The sound is OK, yet the picture stays black. GraphEdit shows that by default the AVI decoder filter is being used, even with rm files. Removing this filter in GraphEdit solves the problem, the picture is OK.
My question is, Does PB offer a way to "disable" a certain filter? Or would there be a way to build a custom graph for a media file?
Any help will be appreciated.

Re: Directshow Filter Selection

Posted: Mon Feb 28, 2005 9:35 am
by traumatic
Here's some code (from the german forums) using a dedicated filtergraph, maybe that helps:

http://forums.purebasic.com/german/viewtopic.php?t=1054

Code: Select all

;
; http://forums.purebasic.com/german/viewtopic.php?t=1054
;
#CLSCTX_INPROC_SERVER        = $1
#VFW_E_NOT_FOUND             = $80040216
#MAX_FILTER_NAME             = 128

Structure FilterInfo
 achName.b[#MAX_FILTER_NAME]
 lpFilterGraph.IFilterGraph
EndStructure

Enumeration
 #PINDIR_INPUT
 #PINDIR_OUTPUT
EndEnumeration

CoInitialize_(0)
Debug CoCreateInstance_(?CLSID_FilterGraph, #NULL,#CLSCTX_INPROC_SERVER,?IID_IGraphBuilder,@lpGB.IGraphBuilder)
Debug lpGB\QueryInterface(?IID_IMediaControl,@lpMC.IMediaControl)

Debug CoCreateInstance_(?CLSID_Source_Filter, #NULL, #CLSCTX_INPROC_SERVER,?IID_IBaseFilter,@lpSource_Filter.IBaseFilter)
Debug CoCreateInstance_(?CLSID_Avi_Decompressor, #NULL, #CLSCTX_INPROC_SERVER,?IID_IBaseFilter,@lpAvi_Decompressor.IBaseFilter)
Debug CoCreateInstance_(?CLSID_VideoRenderer, #NULL, #CLSCTX_INPROC_SERVER,?IID_IBaseFilter,@lpVRender.IBaseFilter)

file.s = "I:\Clock.avi"

; SOURCE Filter

Dim wavFile.w(Len(file))
MultiByteToWideChar_(#CP_ACP, 0, file, -1, wavFile(), Len(file))
Debug lpGB\AddSourceFilter(@wavFile(), @wavFile(), @lpSource_Filter)
lpSource_Filter\EnumPins(@lpNUM.IEnumPins)
While lpNUM\Next(1,@lpPin.IPin,0) = #S_OK
 lpPin\QueryDirection(@a)
 If a = #PINDIR_OUTPUT
  lpSource_FilterPinOut = lpPin
 EndIf
Wend
Debug lpSource_FilterPinOut

;AVI_Decompressor

Debug lpGB\AddFilter(lpAvi_Decompressor, @"AVI_Decompressor")
lpAvi_Decompressor\EnumPins(@lpNUM.IEnumPins)
While lpNUM\Next(1,@lpPin.IPin,0) = #S_OK
 lpPin\QueryDirection(@a)
 If a = #PINDIR_OUTPUT
  lpAvi_DecompressorPinOut = lpPin
 EndIf
 If a = #PINDIR_INPUT
   lpAvi_DecompressorPinIn  = lpPin
 EndIf
Wend
Debug lpAvi_DecompressorPinIn
Debug lpAvi_DecompressorPinOut

; Renderer

Debug lpGB\AddFilter(lpVRender, @"Video_Renderer")
lpVRender\EnumPins(@lpNUM.IEnumPins)
While lpNUM\Next(1,@lpPin.Ipin,0) = #S_OK
 lpPin\QueryDirection(@a)
If a =  #PINDIR_INPUT
 lpVRenderPinIn = lpPin
EndIf
Wend

Debug lpVRenderPinIn

; Pins verbinden

Debug lpGB\Connect(lpSource_FilterPinOut,lpAvi_DecompressorPinIn)
Debug lpGB\Connect(lpAvi_DecompressorPinOut,lpVRenderPinIn)

; Verwendete Filter anzeigen

Debug lpGB\EnumFilters(@lpEnum.IEnumFilters)
While lpEnum\Next(1,@lpFilter.IBaseFilter,0) = #S_OK
 lpFilter\QueryFilterinfo(@info.FilterInfo)
 Debug PeekS(@info\achName)
Wend

; Wiedergabe starten

lpMC\Run()

; Freigabe

lpFilter\Release()
lpEnum\Release()
lpPin\Release()
lpNUM\Release()
lpVRender\Release()
lpAvi_Decompressor\Release()
lpSource_Filter\Release()
lpMC\Release()
lpGB\Release()

CoUninitialize_()

DataSection
 CLSID_FilterGraph:
 Data.l $E436EBB3
 Data.w $524F,$11CE
 Data.b $9F,$53,$00,$20,$AF,$0B,$A7,$70
 IID_IGraphBuilder:
 Data.l $56A868A9
 Data.W $0AD4,$11CE
 Data.b $B0,$3A,$00,$20,$AF,$0B,$A7,$70
 CLSID_Source_Filter:
 Data.l $D3588AB0
 Data.w $0781,$11CE
 Data.b $B0,$3A,$00,$20,$AF,$0B,$A7,$70
 CLSID_Avi_Splitter:
 Data.l $1B544C20
 Data.w $FD0B,$11CE
 Data.b $8C,$63,$00,$AA,$00,$44,$B5,$1E
 IID_IBaseFilter:
 Data.l $56A86895
 Data.w $0AD4,$11CE
 Data.b $B0,$3A,$00,$20,$AF,$0B,$A7,$70
 CLSID_Avi_Decompressor:
 Data.l $CF49D4E0
 Data.w $1115,$11CE
 Data.b $B0,$3A,$00,$20,$AF,$0B,$A7,$70
 CLSID_VideoRenderer:
 Data.l $70E102B0
 Data.w $5556,$11CE
 Data.b $97,$C0,$00,$AA,$00,$55,$59,$5A
 IID_IMediaControl:
 Data.l $56A868B1
 Data.w $0AD4,$11CE
 Data.b $B0,$3A,$00,$20,$AF,$0B,$A7,$70
EndDataSection 

Posted: Mon Feb 28, 2005 5:02 pm
by normen
This looks exactly like what I was hoping to find. I'll try and let you guys know.
Thanks for the help.

Posted: Tue Mar 08, 2005 4:52 pm
by normen
Hey, it works. Thanks for your help!

Posted: Thu Mar 10, 2005 7:26 pm
by normen
I have another question. For debug purposes, is there a simple way in PureBasic to either save the used gragh to a .grf file to be opened later in GraphEdit or add the running graph to the Running Objects Table in order to connect GraphEdit to the graph.
I did find c++ functions on the Microsoft website for this, but neither am I overly familiar with c++ nor do I know PureBasic well enough to convert these funtions from c++.

Posted: Mon Mar 14, 2005 2:33 pm
by traumatic
normen wrote:[...] or add the running graph to the Running Objects Table in order to connect GraphEdit to the graph.
Here's the MS-code to add a graph to the table
(see http://forums.purebasic.com/german/view ... 6301#26301 for further explanations in german)

Code: Select all

#ROTFLAGS_REGISTRATIONKEEPSALIVE = $01

Structure WCHAR
  c.w[#MAX_PATH]
EndStructure

Procedure.l AddToRot(*pUnkGraph.IUnknown, *pdwRegister.l)
  *pMoniker.IMoniker
  *pROT.IRunningObjectTable

  If GetRunningObjectTable_(0, @*pROT) <> 0
    ProcedureReturn #E_FAIL
  EndIf

  sz.s = "FilterGraph "+LCase(RSet(Hex(*pUnkGraph), 8, "0"))+" pid "+LCase(RSet(Hex(GetCurrentProcessId_()), 8, "0"))
  MultiByteToWideChar_(#CP_ACP, 0, sz, -1, @wsz.WCHAR, Len(sz))

  MultiByteToWideChar_(#CP_ACP, 0, "!", -1, @wsz2.WCHAR, 1)
  hr.l = CreateItemMoniker_(wsz2, wsz, @*pMoniker)

  If hr = 0
    hr = *pROT\Register(#ROTFLAGS_REGISTRATIONKEEPSALIVE, *pUnkGraph, *pMoniker, *pdwRegister)
    *pMoniker\Release()
  EndIf

  *pROT\Release()
  ProcedureReturn hr
EndProcedure 
Don't forget to Revoke() and Release() the RunningObjectTable once done.

BTW: Does anyone have a good (a really good ;)) idea to simplify the widechar mess?

Posted: Mon Mar 14, 2005 5:05 pm
by normen

Posted: Mon Mar 14, 2005 11:19 pm
by traumatic
You're welcome :)

Posted: Tue Mar 15, 2005 8:57 am
by traumatic
traumatic wrote:BTW: Does anyone have a good (a really good ;)) idea to simplify the widechar mess?
Maybe something like this:

Code: Select all

Procedure.l L(string.s)
  *out = AllocateMemory(Len(string)*2 * #SIZEOF_WORD)
  MultiByteToWideChar_(#CP_ACP, 0, string, -1, *out, Len(string))  
  ProcedureReturn *out  
EndProcedure

Code: Select all

.
.
.

Code: Select all

  wsz.l = L("FilterGraph "+LCase(RSet(Hex(*pUnkGraph), 8, "0"))+" pid "+LCase(RSet(Hex(GetCurrentProcessId_()), 8, "0")))
  hr.l  = CreateItemMoniker_(L("!"), wsz, @*pMoniker)