我使用Directshow Lib在C#.NET4.0的Windows应用程序中开发,用于使用webcam录制视频。在视频录制中,我通过在BufferCB中绘制帧并将我的叠加位图放在帧上来放置叠加文本。
这个带叠加层的应用程序运行正常。 但是几天后覆盖文本没有出现所以我试图找出问题,然后我意识到BufferCB没有接到电话。 SetCallback()函数返回0意味着它没有错误。那么为什么BufferCB没有得到调用?
修改
按钮点击代码开始录制,配置samplegrabber获取视频大小信息等。
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;
}