使用 DirectShowNet 寻找关键帧
我的任务是:创建一个图表,将 SampleGrabber 附加到它,并在构建图表后使用 IMediaSeeking 界面抓取关键帧。
以下是我所做的: 在 Main 方法中:
Type comType = Type.GetTypeFromCLSID ( new Guid ( "e436ebb3-524f-11ce-9f53-0020af0ba770" ) );
IGraphBuilder graphBuilder = (IGraphBuilder) Activator.CreateInstance ( comType );
comType = Type.GetTypeFromCLSID ( new Guid ( "C1F400A0-3F08-11d3-9F0B-006008039E37" ) );
ISampleGrabber sampleGrabber = (ISampleGrabber) Activator.CreateInstance ( comType );
graphBuilder.AddFilter ( (IBaseFilter) sampleGrabber, "samplegrabber" );
AMMediaType mediaType = new AMMediaType ( );
mediaType.majorType = MediaType.Video;
mediaType.subType = MediaSubType.RGB24;
mediaType.formatType = FormatType.VideoInfo;
sampleGrabber.SetMediaType ( mediaType );
int hr = graphBuilder.RenderFile ( @"D:\test.wmv", null );
IMediaEventEx mediaEvent = (IMediaEventEx) graphBuilder;
IMediaControl mediaControl = (IMediaControl) graphBuilder;
IVideoWindow videoWindow = (IVideoWindow) graphBuilder;
IBasicAudio basicAudio = (IBasicAudio) graphBuilder;
videoWindow.put_AutoShow ( OABool.False );
basicAudio.put_Volume ( -10000 );
sampleGrabber.SetOneShot ( false );
sampleGrabber.SetBufferSamples ( true );
//the same object has implemented the ISampleGrabberCB interface.
//0 sets the callback to the ISampleGrabberCB::SampleCB() method.
sampleGrabber.SetCallback (this, 0);
mediaControl.Run ( );
EventCode eventCode;
mediaEvent.WaitForCompletion ( -1, out eventCode );
Marshal.ReleaseComObject ( sampleGrabber );
Marshal.ReleaseComObject ( graphBuilder );
在 SampleCB() 回调方法中:
public int SampleCB ( double sampleTime, IMediaSample mediaSample )
{
Console.WriteLine ( "SampleCB Callback" );
Console.WriteLine ( mediaSample.IsSyncPoint ( ) + " " + mediaSample.GetActualDataLength() );
//check if its a keyframe using mediaSample.IsSyncPoint()
//and convert the buffer into image and save it.
return 0;
}
因此,我已经设置了这些内容。现在,当我运行该程序时,一切都会正确加载。但回调仅被调用一次,然后渲染就会停止。不再渲染,也不再回调。 我尝试了另一个回调方法 ISampleGrabber::BufferCB() 以查看它是否遵循相同的命运。但不!每次抓取帧并渲染视频直到结束时都会调用 BufferCB()。
我做错了什么?对此有何建议? 谢谢 :)
My task is : I create a graph, attach a SampleGrabber to it, and grab the keyframes using the IMediaSeeking interface after building the graph.
The following is what I have done :
In the Main method :
Type comType = Type.GetTypeFromCLSID ( new Guid ( "e436ebb3-524f-11ce-9f53-0020af0ba770" ) );
IGraphBuilder graphBuilder = (IGraphBuilder) Activator.CreateInstance ( comType );
comType = Type.GetTypeFromCLSID ( new Guid ( "C1F400A0-3F08-11d3-9F0B-006008039E37" ) );
ISampleGrabber sampleGrabber = (ISampleGrabber) Activator.CreateInstance ( comType );
graphBuilder.AddFilter ( (IBaseFilter) sampleGrabber, "samplegrabber" );
AMMediaType mediaType = new AMMediaType ( );
mediaType.majorType = MediaType.Video;
mediaType.subType = MediaSubType.RGB24;
mediaType.formatType = FormatType.VideoInfo;
sampleGrabber.SetMediaType ( mediaType );
int hr = graphBuilder.RenderFile ( @"D:\test.wmv", null );
IMediaEventEx mediaEvent = (IMediaEventEx) graphBuilder;
IMediaControl mediaControl = (IMediaControl) graphBuilder;
IVideoWindow videoWindow = (IVideoWindow) graphBuilder;
IBasicAudio basicAudio = (IBasicAudio) graphBuilder;
videoWindow.put_AutoShow ( OABool.False );
basicAudio.put_Volume ( -10000 );
sampleGrabber.SetOneShot ( false );
sampleGrabber.SetBufferSamples ( true );
//the same object has implemented the ISampleGrabberCB interface.
//0 sets the callback to the ISampleGrabberCB::SampleCB() method.
sampleGrabber.SetCallback (this, 0);
mediaControl.Run ( );
EventCode eventCode;
mediaEvent.WaitForCompletion ( -1, out eventCode );
Marshal.ReleaseComObject ( sampleGrabber );
Marshal.ReleaseComObject ( graphBuilder );
In the SampleCB() callback method :
public int SampleCB ( double sampleTime, IMediaSample mediaSample )
{
Console.WriteLine ( "SampleCB Callback" );
Console.WriteLine ( mediaSample.IsSyncPoint ( ) + " " + mediaSample.GetActualDataLength() );
//check if its a keyframe using mediaSample.IsSyncPoint()
//and convert the buffer into image and save it.
return 0;
}
Thus, I have set up the things. Now, when i run the program, everything loads correctly. But the callback is called only once, and then the rendering stops. No more rendering and no more callbacks.
I had tried the another callback method ISampleGrabber::BufferCB() to see if it follows the same fate. But no! BufferCB() is called everytime a frame is grabbed and the video is rendered till the end.
What am I doing wrong? Any suggestions on this?
Thank you :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好吧..我终于能够解决这个问题了。我会在这里描述它,以防对其他人有帮助。
我实际上并没有在回调方法中释放 IMediaSample 对象。这是必须要做的,因为它是一个 COM 对象。
只需将 Marshal.ReleaseComObject() 添加到我的 SampleCB() 回调方法中,现在每次 SampleGrabber 抓取样本时都会调用它。
我现在面临另一个问题。然而,我为此发表了另一篇文章,因为它与这个问题并不完全相关。
ok..I have finally been able to solve that problem. I would describe it here in case it helps anyone else.
I was not actually releasing the IMediaSample object in the callback method. That is a must to do, it being a COM object.
On simply adding the Marshal.ReleaseComObject() to my SampleCB() callback method, it is now called everytime the SampleGrabber grabs a sample.
I am facing another issue now. However, I have made another post for that as it doesnt totally relate to this question.