I'm trying to learn C# net. Cause I already know OO PHP some Java and C++ (which i never really used because of manual memory handling)
I was thinking I'm going to start with something useful instead of another book full of artificial problems. I was thinking about simple house monitoring.
I do some googling and grabbed DirectShowNET.
Compiled it course I'm on win7 64b.
Compiled CaptureWMV sample, look at the code and for 12 hour tried to add audio capture to it, but it always crush when I try to use not video only codec.
I googled for working example but couldn't find any.(audio only-yes, video only-yes, but both-nowhere)
Here is my slightly modified code. I'm for sure doing something stupid, but will be very glad if someone point me in the right direction.
Take close look at commented code near
(...)AddSourceFilterForMoniker(devAudio.Mon(...)
This is wrong i know but how to do it right?
using System;
using System.Runtime.InteropServices;
using DirectShowLib;
namespace AsfFilter
{
internal class Capture: IDisposable
{
#region Member variables
/// <summary> graph builder interface. </summary>
private IFilterGraph2 m_FilterGraph = null;
IMediaControl m_mediaCtrl = null;
/// <summary> Set by async routine when it captures an image </summary>
private bool m_bRunning = false;
#if DEBUG
DsROTEntry m_rot = null;
#endif
#endregion
/// <summary> release everything. </summary>
public void Dispose()
{
GC.SuppressFinalize(this);
CloseInterfaces();
}
~Capture()
{
Dispose();
}
/// <summary>
/// Create capture object
/// </summary>
/// <param name="iDeviceNum">Zero based index of capture device</param>
/// <param name="szFileName">Output ASF file name</param>
public Capture(int iDeviceNum, int iAudioNum,string szOutputFileName)
{
DsDevice [] capDevices;
DsDevice [] audioCapDevices;
// Get the collection of video devices
capDevices = DsDevice.GetDevicesOfCat( FilterCategory.VideoInputDevice );
audioCapDevices = DsDevice.GetDevicesOfCat(FilterCategory.AudioInputDevice);
if (iDeviceNum + 1 > capDevices.Length)
{
throw new Exception("No video capture devices found at that index!");
}
if (iAudioNum + 1 > audioCapDevices.Length)
{
throw new Exception("No audio capture devices found at that index!");
}
try
{
// Set up the capture graph
SetupGraph( capDevices[iDeviceNum], audioCapDevices[iDeviceNum], szOutputFileName);
m_bRunning = false;
}
catch
{
Dispose();
throw;
}
}
// Start the capture graph
public void Start()
{
if (!m_bRunning)
{
int hr = m_mediaCtrl.Run();
Marshal.ThrowExceptionForHR( hr );
m_bRunning = true;
}
}
// Pause the capture graph.
// Running the graph takes up a lot of resources. Pause it when it
// isn't needed.
public void Pause()
{
if (m_bRunning)
{
IMediaControl mediaCtrl = m_FilterGraph as IMediaControl;
int hr = mediaCtrl.Pause();
Marshal.ThrowExceptionForHR( hr );
m_bRunning = false;
}
}
/// <summary> build the capture graph. </summary>
private void SetupGraph(DsDevice dev, DsDevice devAudio, string szOutputFileName)
{
int hr;
IBaseFilter capFilter = null;
IBaseFilter asfWriter = null;
IBaseFilter audFilter = null;
ICaptureGraphBuilder2 capGraph = null;
// Get the graphbuilder object
m_FilterGraph = (IFilterGraph2)new FilterGraph();
#if DEBUG
m_rot = new DsROTEntry( m_FilterGraph );
#endif
try
{
// Get the ICaptureGraphBuilder2
capGraph = (ICaptureGraphBuilder2) new CaptureGraphBuilder2();
// Start building the graph
hr = capGraph.SetFiltergraph( m_FilterGraph );
Marshal.ThrowExceptionForHR( hr );
// Add the capture device to the graph
//hr = m_FilterGraph.AddSourceFilterForMoniker(devAudio.Mon, null, devAudio.Name, out capFilter);
//Marshal.ThrowExceptionForHR(hr);
hr = m_FilterGraph.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out capFilter);
Marshal.ThrowExceptionForHR( hr );
asfWriter = ConfigAsf(capGraph, szOutputFileName);
hr = capGraph.RenderStream(null, null, capFilter, null, asfWriter);
Marshal.ThrowExceptionForHR( hr );
m_mediaCtrl = m_FilterGraph as IMediaControl;
}
finally
{
if (capFilter != null)
{
Marshal.ReleaseComObject(capFilter);
capFilter = null;
}
if (asfWriter != null)
{
Marshal.ReleaseComObject(asfWriter);
asfWriter = null;
}
if (capGraph != null)
{
Marshal.ReleaseComObject(capGraph);
capGraph = null;
}
}
}
private IBaseFilter ConfigAsf(ICaptureGraphBuilder2 capGraph, string szOutputFileName)
{
IFileSinkFilter pTmpSink = null;
IBaseFilter asfWriter = null;
int hr = capGraph.SetOutputFileName( MediaSubType.Asf, szOutputFileName, out asfWriter, out pTmpSink);
Marshal.ThrowExceptionForHR( hr );
try
{
IConfigAsfWriter lConfig = asfWriter as IConfigAsfWriter;
// Windows Media Video 8 for Dial-up Modem (No audio, 56 Kbps)
// READ THE README for info about using guids
//WMProfile_V80_56VideoOnly
Guid cat = new Guid(0x6e2a6955, 0x81df, 0x4943, 0xba, 0x50, 0x68, 0xa9, 0x86, 0xa7, 0x8, 0xf6);
//WMProfile_V80_BESTVBRVideo
Guid bat = new Guid(0x48439ba, 0x309c, 0x440e, 0x9c, 0xb4, 0x3d, 0xcc, 0xa3, 0x75, 0x64, 0x23);
//WMProfile_V80_288VideoOnly
Guid vot = new Guid(0x8c45b4c7, 0x4aeb, 0x4f78, 0xa5, 0xec, 0x88, 0x42, 0xb, 0x9d, 0xad, 0xef);
//WMProfile_V80_56Video
Guid vau = new Guid(0x254E8A96, 0x2612, 0x405C, 0x80, 0x39, 0xf0, 0xBF, 0x72, 0x5C, 0xED, 0x7D);
//WMProfile_V80_288MonoAudio
Guid aon = new Guid(0x7ea3126d, 0xe1ba, 0x4716, 0x89, 0xaf, 0xf6, 0x5c, 0xee, 0xc, 0xc, 0x67);
hr = lConfig.ConfigureFilterUsingProfileGuid(cat);
//hr = lConfig.ConfigureFilterUsingProfileGuid(W288Video);
Marshal.ThrowExceptionForHR( hr );
}
finally
{
Marshal.ReleaseComObject(pTmpSink);
}
return asfWriter;
}
/// <summary> Shut down capture </summary>
private void CloseInterfaces()
{
int hr;
try
{
if( m_mediaCtrl != null )
{
// Stop the graph
hr = m_mediaCtrl.Stop();
m_bRunning = false;
}
}
catch {}
#if DEBUG
// Remove graph from the ROT
if ( m_rot != null )
{
m_rot.Dispose();
m_rot = null;
}
#endif
if (m_FilterGraph != null)
{
Marshal.ReleaseComObject(m_FilterGraph);
m_FilterGraph = null;
}
}
}
}
I don't want to use c++ code for this because of memory management and DirectShowNet docs are very... minimalistic. And I can't really understand the idea behind "pin's". Maybe I must completely resign from using ICaptureGraphBuilder2 and try to do it hard way.
THIS IS MY FIRST ENCOUNTER WITH C# - PLEASE REMEMBER THIS!
try this. you can add the sourceFilt and aufilter to the graphbuilder, by using graphbuilder.addFilter(aufilter,"Name Here")
graphbuilder.addFilter(sourceFilt,"Name Here")
, and forget to mention sourceFilt and aufilter is an IBaseFilter
Dim classEnum As IEnumMoniker = Nothing
Dim moniker As IMoniker() = New IMoniker(0) {}
Dim devEnum As ICreateDevEnum = CType(New CreateDevEnum, ICreateDevEnum)
hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, classEnum, 0)
Marshal.ReleaseComObject(devEnum)
If classEnum.Next(moniker.Length, moniker, IntPtr.Zero) = 0 Then
Dim iid As Guid = GetType(IBaseFilter).GUID
moniker(0).BindToObject(Nothing, Nothing, iid, source)
End If
sourceFilt = CType(source, IBaseFilter)
Dim classEnum2 As IEnumMoniker = Nothing
Dim moniker2 As IMoniker() = New IMoniker(0) {}
Dim devEnum2 As ICreateDevEnum = CType(New CreateDevEnum, ICreateDevEnum)
hr = devEnum2.CreateClassEnumerator(FilterCategory.AudioInputDevice, classEnum2, 0)
Marshal.ReleaseComObject(devEnum2)
If classEnum2.Next(moniker2.Length, moniker2, IntPtr.Zero) = 0 Then
Dim iid As Guid = GetType(IBaseFilter).GUID
moniker2(0).BindToObject(Nothing, Nothing, iid, sobject)
End If
aufilter = CType(sobject, IBaseFilter)