使用DirectShowNet寻找关键帧

使用DirectShowNet寻找关键帧

本文介绍了使用DirectShowNet寻找关键帧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的任务是:创建一个图形,将SampleGrabber附加到该图形上,并在构建图形后使用IMediaSeeking界面获取关键帧.

My task is : I create a graph, attach a SampleGrabber to it, and grab the keyframes using the IMediaSeeking interface after building the graph.

以下是我所做的:在Main方法中:

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 );

在SampleCB()回调方法中:

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;
    }

因此,我已经完成了设置.现在,当我运行程序时,一切都正确加载.但是回调仅被调用一次,然后呈现停止.没有更多的渲染,也没有更多的回调.我尝试了另一个回调方法ISampleGrabber :: BufferCB()来查看它是否遵循相同的命运.但不是!每次抓取一帧并将视频渲染到最后时,都会调用BufferCB().

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 :)

推荐答案

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

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.

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

On simply adding the Marshal.ReleaseComObject() to my SampleCB() callback method, it is now called everytime the SampleGrabber grabs a sample.

public int SampleCB ( double sampleTime, IMediaSample mediaSample )
{
    Console.WriteLine ( "SampleCB Callback" );
    Console.WriteLine ( mediaSample.IsSyncPoint ( ) + " " );

        /* other code */
    Marshal.ReleaseComObject ( mediaSample );
    return 0;
}

我现在面临另一个问题.但是,我为此发表了另一篇文章,因为它并不完全与此问题相关.

I am facing another issue now. However, I have made another post for that as it doesnt totally relate to this question.

这篇关于使用DirectShowNet寻找关键帧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 22:07