我在带有 Directshow Lib 的 C#.NET4.0 中的 Windows 应用程序中开发,用于使用网络摄像头录制视频。在视频录制期间,我通过在 BufferCB 中抓取框架来放置覆盖文本,并将覆盖位图放在框架上。
这个带有覆盖的应用程序运行良好。但是几天后覆盖文本没有出现,所以我试图找出问题然后我意识到 BufferCB 没有接到电话。SetCallback() 函数返回 0 表示其中没有错误。那么为什么 BufferCB 没有得到调用?
编辑
用于开始录制的按钮单击代码,配置采样器获取视频大小信息等。
private void button1_Click(object sender, EventArgs e)
{
jpg.RotateFlip(RotateFlipType.RotateNoneFlipY);
//jpgdata = jpg.LockBits(new Rectangle(0, 0, jpg.Width, jpg.Height), ImageLockMode.ReadWrite, jpg.PixelFormat);
AvailableAudioInputDevices = new List<DsDevice>();
DsDevice[] audioInputDevices = DsDevice.GetDevicesOfCat(FilterCategory.AudioInputDevice);
AvailableAudioInputDevices.AddRange(audioInputDevices);
AvailableVideoInputDevices = new List<DsDevice>();
DsDevice[] videoInputDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
AvailableVideoInputDevices.AddRange(videoInputDevices);
Graph = (IFilterGraph2)new FilterGraph();
captureGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
hr = captureGraph.SetFiltergraph(Graph);
DsError.ThrowExceptionForHR(hr);
hr = captureGraph.SetOutputFileName(MediaSubType.Asf, "qwe.wmv", out pMux, out pFilter);
DsError.ThrowExceptionForHR(hr);
hr = Graph.AddSourceFilterForMoniker(AvailableAudioInputDevices.First().Mon, null, AvailableAudioInputDevices.First().Name, out capFilter);
DsError.ThrowExceptionForHR(hr);
//ConfigProfileFromFile(pMux, "b.prx");
hr = captureGraph.RenderStream(PinCategory.Capture, MediaType.Audio, capFilter, null, pMux);
DsError.ThrowExceptionForHR(hr);
hr = Graph.AddSourceFilterForMoniker(AvailableVideoInputDevices.First().Mon, null, AvailableVideoInputDevices.First().Name, out capFilter);
DsError.ThrowExceptionForHR(hr);
#region code for init. preview window and sample grabber
mediaControl = (IMediaControl)Graph;
mediaEventEx = (IMediaEventEx)Graph;
mediaEventEx.SetNotifyWindow(pic.Handle, WM_GRAPHNOTIFY, IntPtr.Zero);
IBaseFilter vmr9preview = null;
vmr9preview = (IBaseFilter)new VideoMixingRenderer9();
hr = Graph.AddFilter(vmr9preview, "VMR9");
DsError.ThrowExceptionForHR(hr);
IVMRFilterConfig9 vmr9Config = (IVMRFilterConfig9)vmr9preview;
vmr9Config.SetRenderingMode(VMR9Mode.Windowless);
vmr9Config.SetNumberOfStreams(1);
vmr9Control = (IVMRWindowlessControl9)vmr9preview;
vmr9Control.SetVideoClippingWindow(pic.Handle);
vmr9Control.SetAspectRatioMode(VMR9AspectRatioMode.None);
var srcRect = new DsRect();
var dstRect = new DsRect(pic.ClientRectangle);
int arWidth, arHeight;
vmr9Control.GetNativeVideoSize(out srcRect.right, out srcRect.bottom, out arWidth, out arHeight);
vmr9Control.SetVideoPosition(srcRect, dstRect);
sampGrabber = new SampleGrabber() as ISampleGrabber;
#endregion
#region code for get video info and config sample grabber
IPin iPinOutSource = DsFindPin.ByDirection(capFilter, PinDirection.Output, 0);
// Configure the sample grabber
IBaseFilter baseGrabFlt = sampGrabber as IBaseFilter;
ConfigureSampleGrabber(sampGrabber);
iPinInFilter = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Input, 0);
iPinOutFilter = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Output, 0);
// Add the frame grabber to the graph
hr = Graph.AddFilter(baseGrabFlt, "Ds.NET Grabber");
DsError.ThrowExceptionForHR(hr);
hr = Graph.Connect(iPinOutSource, iPinInFilter);
DsError.ThrowExceptionForHR(hr);
// Get the default video renderer
ibfRenderer = (IBaseFilter)new VideoRendererDefault();
// Add it to the graph
hr = Graph.AddFilter(ibfRenderer, "Ds.NET VideoRendererDefault");
DsError.ThrowExceptionForHR(hr);
iPinInDest = DsFindPin.ByDirection(ibfRenderer, PinDirection.Input, 0);
// Connect the graph. Many other filters automatically get added here
hr = Graph.Connect(iPinOutFilter, iPinInDest);
DsError.ThrowExceptionForHR(hr);
SaveSizeInfo(sampGrabber);
hr = Graph.RemoveFilter(baseGrabFlt);
DsError.ThrowExceptionForHR(hr);
hr = Graph.Disconnect(iPinOutSource);
DsError.ThrowExceptionForHR(hr);
hr = Graph.RemoveFilter(ibfRenderer);
DsError.ThrowExceptionForHR(hr);
hr = Graph.Disconnect(iPinInDest);
DsError.ThrowExceptionForHR(hr);
#endregion
ConfigProfileFromFile(pMux, "b.prx");
hr = Graph.AddFilter(capFilter, "VMR9");
DsError.ThrowExceptionForHR(hr);
hr = Graph.AddFilter(baseGrabFlt, "Ds.NET Grabber");
DsError.ThrowExceptionForHR(hr);
hr = captureGraph.RenderStream(PinCategory.Preview, MediaType.Video, capFilter, null, vmr9preview);
DsError.ThrowExceptionForHR(hr);
hr = captureGraph.RenderStream(PinCategory.Capture, MediaType.Video, capFilter, null, pMux);
DsError.ThrowExceptionForHR(hr);
m_mediaCtrl = Graph as IMediaControl;
SetupBitmap();
m_mediaCtrl.Run();
//timer1.Start();
}
Config Sample Grabber 方法
private void ConfigureSampleGrabber(ISampleGrabber sampGrabber)
{
int hr;
AMMediaType media = new AMMediaType();
// Set the media type to Video/RBG24
media.majorType = MediaType.Video;
media.subType = MediaSubType.RGB24;
media.formatType = FormatType.VideoInfo;
hr = sampGrabber.SetMediaType(media);
DsError.ThrowExceptionForHR(hr);
DsUtils.FreeAMMediaType(media);
media = null;
// Configure the samplegrabber
hr = sampGrabber.SetCallback(this, 1);
DsError.ThrowExceptionForHR(hr);
}
BufferCB 和 SampleCB
int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample)
{
Marshal.ReleaseComObject(pSample);
return 0;
}
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);
/// <summary> buffer callback, COULD BE FROM FOREIGN THREAD. </summary>
int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
{
CopyMemory(pBuffer, bmpData.Scan0, bmpData.Stride*20);
return 0;
}