I recently bought a hardware mpeg2 encoder card, the asus edh2-100, and after
hours of tries i was finally able to construct the capture graph in Grahedit
and now i am able to capture mpeg2 files by hardware encoder only by running a
graph in graphedit. So now the problem is porting this to vb.net, but
unfortunately i am still a newbie into c#, altough since know tons about
vb.net i am more or less able to understand a bit c# code, so i was fiddling
with the sample project "DxTuner" that came with DirectShowSamples-2007-July,
and i was able to add to the capture graph the hardware encoder devide of my
card (it's filter type is WDMStreamingMultiplexerDevices). By analyzing the
code i was able to figure out more or less how the filters are connected, and
the file writer as well, altough i am having a lot of problems being able to
connect the WDMStreamingMultiplexerDevice to the tv tuner device and set up
the file writer to receive the feed of this hardware encoder device...
Can someone please tell me how to i connect this device to the "ICS audio" and
"analog ITU video" pins ? I already spent the entire day using google for
this, and i found absolutly no code showing how to use hardware encoder in tv
capture programs, and the code in Dxtuner only connects the Capture pi. Here's
a screenshot of the graph i built in graphedit and in which i successfully
record mpeg2 files by hardware :
While there may be ways to have the automatic graph building functions produce
this graph for you, it may be simpler in the long run to manually add the 6
filters to the graph and connect them yourself. Check out the docs for
IFilterGraph.AddFilter and IPin.Connect. You might find the utility routines
we have created useful as well (like DsFindPin from DSUtils or ConnectFilters
from FilterGraphTools.cs).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
FINALLY i was able to fully code this in visual basic.net, jeez it was almost
two ENTIRE days of googling, tweaking and tons of frustations, for about 2-3
times i was almost about to give up but finally i was able to code this, jeez
i never tought it was SO difficult, this is all because there is almost no
vb.net code on the internet about the directshow.net library, and some of the
problems i had was related to bad convertions from c# to vb.net with online
converters. And yes i had to use your advice in connecting the pins manually,
but i also had a huge help of the generated code in graphedit plus program
even tought just the code itself wouldn't work even on c#...
In fact as soon as i saw your advice i tried what you said and i meanwhile
discovered the DxLogoVB application, the ONLY one i found so far coded in
vb.net using this library and this is what helped me the most :) I even now
know how to set the channel and fiddling with the crossbar.
There is two major things i need to do for now :
Create a second graph to connect to the streaming mpeg2 hardware encoded file
so that i am able to preview the mpeg2 that is being encoded by hardware, it
seems it's necessary to have a second graph running after the first one
starts, i hope i will be able to do this myself, but so far the current
priority is the next goal :
Being able to set by code the settings of the hardware encoder (unfortunately
it's not possible to do this the same way as the channel change is done with
IAMTVTuner). I noticed that the settings of the WDMStreamingMultiplexerDevice
are kept in the same session of Graphedit in which i change them, but even if
i save the graph file and reload it later on GraphEdit after graphedit was
closed, the settings i changed manually using the dialog pages are NOT kept
they keep getting back to the defaults.
But i really need a way to change the hardware encoder settings by code
without having to change the settings myself in the property dialog pages
everytime i start the vb.net program... Let's presume that in runtime i set
myself the settings in the dialog pages of the filter, after i do that is it
possible to "capture" or save the current contents of the dialog pages'
settings to a variable so that i can "fill" the filter's settings dialog pages
with the contents of the previously saved variable just using code? Maybe
there is a way to do this or not ? I am sure there is a way since the program
that came with my capture card is able to change those settings in the
hardware encoder device... Please if you or someone else is able to help me on
this...
Well.. since yesterday until this morning i spent several hours in trying
precisely that method you say, about direct pin connection and i am really
almost giving up, this is the hardest thing i have ever tried to do, specially
because i understand very few about c# altough i was still able to try douzens
of snippets i found online about getpins from filters and absolutly nothing
worked. For example i tired this code generated by a program that loads grf
files :
//Don't forget to add reference to DirectShowLib in your project.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using DirectShowLib;
namespace graphcode
{
class Program
{
static void checkHR(int hr, string msg)
{
if (hr < 0)
{
Console.WriteLine(msg);
DsError.ThrowExceptionForHR(hr);
}
}
static void BuildGraph(IGraphBuilder pGraph)
{
int hr = 0;
static void Main(string args)
{
try
{
IGraphBuilder graph = (IGraphBuilder)new FilterGraph();
Console.WriteLine("Building graph...");
BuildGraph(graph);
Console.WriteLine("Running...");
IMediaControl mediaControl = (IMediaControl)graph;
IMediaEvent mediaEvent = (IMediaEvent)graph;
int hr = mediaControl.Run();
checkHR(hr, "Can't run the graph");
bool stop = false;
int n = 0;
while (!stop)
{
System.Threading.Thread.Sleep(500);
Console.Write(".");
EventCode ev;
IntPtr p1, p2;
if (mediaEvent.GetEvent(out ev, out p1, out p2, 0) == 0)
{
if (ev == EventCode.Complete || ev == EventCode.UserAbort)
{
Console.WriteLine("Done!");
stop = true;
}
else
if (ev == EventCode.ErrorAbort)
{
Console.WriteLine("An error occured: HRESULT={0:X}", p1);
mediaControl.Stop();
stop = true;
}
mediaEvent.FreeEventParams(ev, p1, p2);
}
// stop after 10 seconds
n++;
if (n > 20)
{
Console.WriteLine("stopping..");
mediaControl.Stop();
stop = true;
}
}
}
catch (COMException ex)
{
Console.WriteLine("COM error: " + ex.ToString());
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.ToString());
}
}
static IPin GetPin(IBaseFilter filter, string pinname)
{
IEnumPins epins;
int hr = filter.EnumPins(out epins);
checkHR(hr, "Can't enumerate pins");
IntPtr fetched = Marshal.AllocCoTaskMem(4);
IPin pins = new IPin;
while (epins.Next(1, pins, fetched) == 0)
{
PinInfo pinfo;
pins.QueryPinInfo(out pinfo);
bool found = (pinfo.name == pinname);
DsUtils.FreePinInfo(pinfo);
if (found)
return pins;
}
checkHR(hr,"");
return null;
}
}
}
(it's not exactly the code from my device but i found that code online and it
matched the one i got generated
Not even this works, simply because the getpins funcion doesn't work and is
unable to find any pins.
By the way with the Dxtuner program i am unable to get the tv audio device,
since it does not show up as a device in FilterCategory.AudioInputDevice
altough it does show up in Graph Edit as a
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
OH NO i forgot to delete the previous message i was still writing earlier in
the day, jeez there isn't a edit function in this forum ? I would like you to
ignore EVERYTHING i said after "Please if you or someone else is able to help
me on this...", because the most recent message i meant to send was just until
that sentence, so just read until there.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I recently bought a hardware mpeg2 encoder card, the asus edh2-100, and after
hours of tries i was finally able to construct the capture graph in Grahedit
and now i am able to capture mpeg2 files by hardware encoder only by running a
graph in graphedit. So now the problem is porting this to vb.net, but
unfortunately i am still a newbie into c#, altough since know tons about
vb.net i am more or less able to understand a bit c# code, so i was fiddling
with the sample project "DxTuner" that came with DirectShowSamples-2007-July,
and i was able to add to the capture graph the hardware encoder devide of my
card (it's filter type is WDMStreamingMultiplexerDevices). By analyzing the
code i was able to figure out more or less how the filters are connected, and
the file writer as well, altough i am having a lot of problems being able to
connect the WDMStreamingMultiplexerDevice to the tv tuner device and set up
the file writer to receive the feed of this hardware encoder device...
Can someone please tell me how to i connect this device to the "ICS audio" and
"analog ITU video" pins ? I already spent the entire day using google for
this, and i found absolutly no code showing how to use hardware encoder in tv
capture programs, and the code in Dxtuner only connects the Capture pi. Here's
a screenshot of the graph i built in graphedit and in which i successfully
record mpeg2 files by hardware :
http://i46.tinypic.com/zmih6e.jpg
While there may be ways to have the automatic graph building functions produce
this graph for you, it may be simpler in the long run to manually add the 6
filters to the graph and connect them yourself. Check out the docs for
IFilterGraph.AddFilter and IPin.Connect. You might find the utility routines
we have created useful as well (like DsFindPin from DSUtils or ConnectFilters
from FilterGraphTools.cs).
FINALLY i was able to fully code this in visual basic.net, jeez it was almost
two ENTIRE days of googling, tweaking and tons of frustations, for about 2-3
times i was almost about to give up but finally i was able to code this, jeez
i never tought it was SO difficult, this is all because there is almost no
vb.net code on the internet about the directshow.net library, and some of the
problems i had was related to bad convertions from c# to vb.net with online
converters. And yes i had to use your advice in connecting the pins manually,
but i also had a huge help of the generated code in graphedit plus program
even tought just the code itself wouldn't work even on c#...
In fact as soon as i saw your advice i tried what you said and i meanwhile
discovered the DxLogoVB application, the ONLY one i found so far coded in
vb.net using this library and this is what helped me the most :) I even now
know how to set the channel and fiddling with the crossbar.
There is two major things i need to do for now :
Create a second graph to connect to the streaming mpeg2 hardware encoded file
so that i am able to preview the mpeg2 that is being encoded by hardware, it
seems it's necessary to have a second graph running after the first one
starts, i hope i will be able to do this myself, but so far the current
priority is the next goal :
Being able to set by code the settings of the hardware encoder (unfortunately
it's not possible to do this the same way as the channel change is done with
IAMTVTuner). I noticed that the settings of the WDMStreamingMultiplexerDevice
are kept in the same session of Graphedit in which i change them, but even if
i save the graph file and reload it later on GraphEdit after graphedit was
closed, the settings i changed manually using the dialog pages are NOT kept
they keep getting back to the defaults.
But i really need a way to change the hardware encoder settings by code
without having to change the settings myself in the property dialog pages
everytime i start the vb.net program... Let's presume that in runtime i set
myself the settings in the dialog pages of the filter, after i do that is it
possible to "capture" or save the current contents of the dialog pages'
settings to a variable so that i can "fill" the filter's settings dialog pages
with the contents of the previously saved variable just using code? Maybe
there is a way to do this or not ? I am sure there is a way since the program
that came with my capture card is able to change those settings in the
hardware encoder device... Please if you or someone else is able to help me on
this...
Well.. since yesterday until this morning i spent several hours in trying
precisely that method you say, about direct pin connection and i am really
almost giving up, this is the hardest thing i have ever tried to do, specially
because i understand very few about c# altough i was still able to try douzens
of snippets i found online about getpins from filters and absolutly nothing
worked. For example i tired this code generated by a program that loads grf
files :
//Don't forget to add reference to DirectShowLib in your project.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using DirectShowLib;
namespace graphcode
{
class Program
{
static void checkHR(int hr, string msg)
{
if (hr < 0)
{
Console.WriteLine(msg);
DsError.ThrowExceptionForHR(hr);
}
}
static void BuildGraph(IGraphBuilder pGraph)
{
int hr = 0;
//graph builder
ICaptureGraphBuilder2 pBuilder = (ICaptureGraphBuilder2)new
CaptureGraphBuilder2();
hr = pBuilder.SetFiltergraph(pGraph);
checkHR(hr, "Can't SetFiltergraph");
Guid CLSID_TridVidTvTuner0001 = new Guid("{266EEE40-6C63-11CF-
8A03-00AA006ECB65}"); //kstvtune.ax
Guid CLSID_TridVidTvAudio0002 = new Guid("{71F96462-78F3-11D0-A18C-
00A0C9118956}"); //ksxbar.ax
Guid CLSID_TridVidCrossbar = new Guid("{71F96460-78F3-11D0-A18C-
00A0C9118956}"); //ksxbar.ax
Guid CLSID_SigmaTelAudioTopology = new Guid("{17CCA71B-
ECD7-11D0-B908-00A0C9223196}"); //ksproxy.ax
Guid CLSID_VideoRenderer = new Guid("{B87BEB7B-8D29-423F-AE4D-6582C10175AC}");
//quartz.dll
//add TridVid TvTuner 0001
IBaseFilter pTridVidTvTuner0001 = (IBaseFilter)Activator.CreateInstance(Type.G
etTypeFromCLSID(CLSID_TridVidTvTuner0001));
hr = pGraph.AddFilter(pTridVidTvTuner0001, "TridVid TvTuner 0001");
checkHR(hr, "Can't add TridVid TvTuner 0001 to graph");
//add TridVid TvAudio 0002
IBaseFilter pTridVidTvAudio0002 = (IBaseFilter)Activator.CreateInstance(Type.G
etTypeFromCLSID(CLSID_TridVidTvAudio0002));
hr = pGraph.AddFilter(pTridVidTvAudio0002, "TridVid TvAudio 0002");
checkHR(hr, "Can't add TridVid TvAudio 0002 to graph");
//connect TridVid TvTuner 0001 and TridVid TvAudio 0002
hr = pGraph.ConnectDirect(GetPin(pTridVidTvTuner0001, "Analog Audio"),
GetPin(pTridVidTvAudio0002, "TVAudio In"), null);
checkHR(hr, "Can't connect TridVid TvTuner 0001 and TridVid TvAudio 0002");
//add TridVid Crossbar
IBaseFilter pTridVidCrossbar = (IBaseFilter)Activator.CreateInstance(Type.GetT
ypeFromCLSID(CLSID_TridVidCrossbar));
hr = pGraph.AddFilter(pTridVidCrossbar, "TridVid Crossbar");
checkHR(hr, "Can't add TridVid Crossbar to graph");
//connect TridVid TvTuner 0001 and TridVid Crossbar
hr = pGraph.ConnectDirect(GetPin(pTridVidTvTuner0001, "Analog Video"),
GetPin(pTridVidCrossbar, "0: Video Tuner In"), null);
checkHR(hr, "Can't connect TridVid TvTuner 0001 and TridVid Crossbar");
//connect TridVid TvAudio 0002 and TridVid Crossbar
hr = pGraph.ConnectDirect(GetPin(pTridVidTvAudio0002, "TVAudio Out"),
GetPin(pTridVidCrossbar, "3: Audio Tuner In"), null);
checkHR(hr, "Can't connect TridVid TvAudio 0002 and TridVid Crossbar");
//add SigmaTel Audio Topology
IBaseFilter pSigmaTelAudioTopology = (IBaseFilter)Activator.CreateInstance(Typ
e.GetTypeFromCLSID(CLSID_SigmaTelAudioTopology));
hr = pGraph.AddFilter(pSigmaTelAudioTopology, "SigmaTel Audio Topology");
checkHR(hr, "Can't add SigmaTel Audio Topology to graph");
//connect TridVid Crossbar and SigmaTel Audio Topology
hr = pGraph.ConnectDirect(GetPin(pTridVidCrossbar, "0: Video Decoder Out"),
GetPin(pSigmaTelAudioTopology, "Analog Video In"), null);
checkHR(hr, "Can't connect TridVid Crossbar and SigmaTel Audio Topology");
//connect TridVid Crossbar and SigmaTel Audio Topology
hr = pGraph.ConnectDirect(GetPin(pTridVidCrossbar, "1: Audio Decoder Out"),
GetPin(pSigmaTelAudioTopology, "Analog Audio In"), null);
checkHR(hr, "Can't connect TridVid Crossbar and SigmaTel Audio Topology");
//add Video Renderer
IBaseFilter pVideoRenderer = (IBaseFilter)Activator.CreateInstance(Type.GetTyp
eFromCLSID(CLSID_VideoRenderer));
hr = pGraph.AddFilter(pVideoRenderer, "Video Renderer");
checkHR(hr, "Can't add Video Renderer to graph");
//add Default DirectSound Device
IBaseFilter pDefaultDirectSoundDevice = (IBaseFilter)new DSoundRender();
hr = pGraph.AddFilter(pDefaultDirectSoundDevice, "Default DirectSound
Device");
checkHR(hr, "Can't add Default DirectSound Device to graph");
//connect SigmaTel Audio Topology and Video Renderer
hr = pGraph.ConnectDirect(GetPin(pSigmaTelAudioTopology, "Capture"),
GetPin(pVideoRenderer, "VMR Input0"), null);
checkHR(hr, "Can't connect SigmaTel Audio Topology and Video Renderer");
//connect SigmaTel Audio Topology and Default DirectSound Device
hr = pGraph.ConnectDirect(GetPin(pSigmaTelAudioTopology, "Audio"),
GetPin(pDefaultDirectSoundDevice, "Audio Input pin (rendered)"), null);
checkHR(hr, "Can't connect SigmaTel Audio Topology and Default DirectSound
Device");
}
static void Main(string args)
{
try
{
IGraphBuilder graph = (IGraphBuilder)new FilterGraph();
Console.WriteLine("Building graph...");
BuildGraph(graph);
Console.WriteLine("Running...");
IMediaControl mediaControl = (IMediaControl)graph;
IMediaEvent mediaEvent = (IMediaEvent)graph;
int hr = mediaControl.Run();
checkHR(hr, "Can't run the graph");
bool stop = false;
int n = 0;
while (!stop)
{
System.Threading.Thread.Sleep(500);
Console.Write(".");
EventCode ev;
IntPtr p1, p2;
if (mediaEvent.GetEvent(out ev, out p1, out p2, 0) == 0)
{
if (ev == EventCode.Complete || ev == EventCode.UserAbort)
{
Console.WriteLine("Done!");
stop = true;
}
else
if (ev == EventCode.ErrorAbort)
{
Console.WriteLine("An error occured: HRESULT={0:X}", p1);
mediaControl.Stop();
stop = true;
}
mediaEvent.FreeEventParams(ev, p1, p2);
}
// stop after 10 seconds
n++;
if (n > 20)
{
Console.WriteLine("stopping..");
mediaControl.Stop();
stop = true;
}
}
}
catch (COMException ex)
{
Console.WriteLine("COM error: " + ex.ToString());
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.ToString());
}
}
static IPin GetPin(IBaseFilter filter, string pinname)
{
IEnumPins epins;
int hr = filter.EnumPins(out epins);
checkHR(hr, "Can't enumerate pins");
IntPtr fetched = Marshal.AllocCoTaskMem(4);
IPin pins = new IPin;
while (epins.Next(1, pins, fetched) == 0)
{
PinInfo pinfo;
pins.QueryPinInfo(out pinfo);
bool found = (pinfo.name == pinname);
DsUtils.FreePinInfo(pinfo);
if (found)
return pins;
}
checkHR(hr,"");
return null;
}
}
}
(it's not exactly the code from my device but i found that code online and it
matched the one i got generated
Not even this works, simply because the getpins funcion doesn't work and is
unable to find any pins.
By the way with the Dxtuner program i am unable to get the tv audio device,
since it does not show up as a device in FilterCategory.AudioInputDevice
altough it does show up in Graph Edit as a
OH NO i forgot to delete the previous message i was still writing earlier in
the day, jeez there isn't a edit function in this forum ? I would like you to
ignore EVERYTHING i said after "Please if you or someone else is able to help
me on this...", because the most recent message i meant to send was just until
that sentence, so just read until there.