使用 DirectShowNet 寻找关键帧

发布于 2024-10-12 21:30:26 字数 2292 浏览 3 评论 0原文

我的任务是:创建一个图表,将 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

迷鸟归林 2024-10-19 21:30:26

好吧..我终于能够解决这个问题了。我会在这里描述它,以防对其他人有帮助。
我实际上并没有在回调方法中释放 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;
}

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

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文