Поиск ключевых кадров с помощью DirectShowNet - PullRequest
1 голос
/ 19 января 2011

Моя задача такова: я создаю график, присоединяю к нему 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 () вызывается каждый раз, когда захватывается кадр и видео воспроизводится до конца.

Что я делаю не так?Есть предложения по этому поводу?Спасибо:)

1 Ответ

2 голосов
/ 24 января 2011

хорошо ... Я наконец-то смог решить эту проблему. Я бы описал это здесь на случай, если это поможет кому-то еще. На самом деле я не выпускал объект 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;
}

У меня сейчас другая проблема. Тем не менее, я сделал еще один пост для этого, поскольку он не имеет никакого отношения к этому вопросу.

...