使用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(),并将video渲染到最后。

我究竟做错了什么? 有什么建议吗? 谢谢 :)

好的..我终于能够解决这个问题了。 我会在这里描述它,以防它帮助其他人。 我实际上并没有在回调方法中释放IMediaSample对象。 这是必须要做的,它是一个COM对象。

只需将Marshal.ReleaseComObject()添加到我的SampleCB()回调方法,现在每次SampleGrabber抓取样本时都会调用它。

 public int SampleCB ( double sampleTime, IMediaSample mediaSample ) { Console.WriteLine ( "SampleCB Callback" ); Console.WriteLine ( mediaSample.IsSyncPoint ( ) + " " ); /* other code */ Marshal.ReleaseComObject ( mediaSample ); return 0; } 

我现在面临另一个问题。 但是,我已经为此发了另一篇文章,因为它与这个问题没有完全相关。