我一直在开发一个使用Directshow.NET的应用程序,并决定开始修补 GraphEd.exe 以找出我需要采取的确切路线。
我想要的最简单版本在上图中(其中“test.mpeg”是“文件编写器”过滤器)。
果然,在 GraphEd 中看起来很简单的事情并不像编码那么简单。几秒钟后,我意识到 directshow 是我不理解的东西。这是我的 C# 代码尝试:
int hr;
IBaseFilter cameraStream = null;
IBaseFilter mpegEncoder = null;
IBaseFilter fileWriter = null;
ICaptureGraphBuilder2 capGraph = null;
filterGraph = (IFilterGraph2)new FilterGraph();
try
{
capGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
hr = capGraph.SetFiltergraph(filterGraph);
Marshal.ThrowExceptionForHR(hr);
hr = filterGraph.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out cameraStream);
Marshal.ThrowExceptionForHR(hr);
IPin cameraData = null;
hr = capGraph.FindPin(cameraStream, PinDirection.Output, PinCategory.Capture, MediaType.Video, true, 0, out cameraData );
//hr = cameraStream.FindPin("Capture", out cameraData);
Marshal.ThrowExceptionForHR(hr);
mpegEncoder = (IBaseFilter)new MJPGEnc();
hr = filterGraph.AddFilter(mpegEncoder, "mpeg encoder");
//hr = filterGraph.FindFilterByName("Microsoft MPEG-2 Video Encoder", out mpegEncoder);
Marshal.ThrowExceptionForHR(hr);
IPin mpegInput = null;
//hr = mpegEncoder.FindPin("Input0", out mpegInput);
hr = capGraph.FindPin(mpegEncoder, PinDirection.Input, null, null, true, 0, out mpegInput);
Marshal.ThrowExceptionForHR(hr);
filterGraph.Connect(cameraData, mpegInput);
IPin mpegOutput = null;
//hr = mpegEncoder.FindPin("Output", out mpegOutput);
hr = capGraph.FindPin(mpegEncoder, PinDirection.Output, null, null, true, 0, out mpegOutput);
Marshal.ThrowExceptionForHR(hr);
//hr = filterGraph.FindFilterByName("File writer", out fileWriter);
fileWriter = (IBaseFilter)new FileWriter();
IFileSinkFilter test = fileWriter as IFileSinkFilter2;
AMMediaType mtype = new AMMediaType();
mtype.majorType = MediaType.Video;
mtype.subType = MediaSubType.RGB24;
mtype.formatPtr = IntPtr.Zero;
test.SetFileName(videoPath, mtype );
IPin fwriterIn = null;
//hr = fileWriter.FindPin("in", out fwriterIn);
hr = capGraph.FindPin(fileWriter, PinDirection.Input, null, null, true, 0, out fwriterIn);
Marshal.ThrowExceptionForHR(hr);
filterGraph.Connect(mpegOutput, fwriterIn);
hr = capGraph.RenderStream(null, null, cameraStream, null, fileWriter); // *** Breaks on this line! ***
Marshal.ThrowExceptionForHR(hr);
mediaControl = filterGraph as IMediaControl;
}
finally
{
if (cameraStream != null)
{
Marshal.ReleaseComObject(cameraStream);
cameraStream = null;
}
if (mpegEncoder != null)
{
Marshal.ReleaseComObject(mpegEncoder);
mpegEncoder = null;
}
if (fileWriter != null)
{
Marshal.ReleaseComObject(fileWriter);
fileWriter = null;
}
if (capGraph != null)
{
Marshal.ReleaseComObject(capGraph);
capGraph = null;
}
}
在编写并查看了我的代码有多荒谬(就编程逻辑而言)之后,我意识到我需要一些帮助。
谁能指导我某种结构化的directshow教程,向我解释事情,就好像我是一个巨大的新手一样,或者可能将我链接到某种处理网络摄像头到文件记录的C#库?我一般不是win32程序员,所以任何减轻痛苦的东西都应该是好的:)
另外,我确实有似乎可以工作的相机设备枚举代码:
private void rescan_camera()
{
comboBox1.Items.Clear();
DsDevice[] cameraDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
for(int i=0; i < cameraDevices.Length; i++) {
comboBox1.Items.Add(cameraDevices[i].Name);
}
if (comboBox1.Items.Count > 0) comboBox1.SelectedIndex = 0;
}
我可以从 DsDevice 获取名字对象数据,我知道这是告诉 directshow 过滤器图表我想从哪里记录的关键部分,但这与我的知识范围有关。
编辑:更新的代码,显示换行符的确切位置。