2011-01-19 33 views
1

我的任務是:我創建一個圖形,爲其添加一個SampleGrabber,並在構建圖形後使用IMediaSeeking界面獲取關鍵幀。使用DirectShowNet尋找關鍵幀

以下是我做了什麼: 在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()在每次抓取幀時調用,視頻渲染直到結束。

我在做什麼錯?對此有何建議? 謝謝:)

回答

2

好的。我終於能夠解決這個問題。我會在這裏描述它,以防其他人幫助。 我實際上並沒有在回調方法中釋放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; 
} 

我現在面臨另一個問題。但是,我已經爲此發表了另一篇文章,因爲它不完全涉及這個問題。