Использование интерфейса обратного вызова C ++ в C # - PullRequest
2 голосов
/ 25 января 2010

Я пишу приложение, которое должно записывать видео с помощью DirectShow - для этого я использую библиотеку взаимодействия DirectShowLib, которая, кажется, прекрасно работает.

Однако теперь мне нужно получить уведомление об обратном вызове, так как образцы записываются в файл, поэтому я могу добавить расширения блока данных. Согласно документации msdn, в C ++ это делается путем реализации интерфейса IAMWMBufferPassCallback и передачи полученного объекта в метод SetNotify интерфейса IAMWMBufferPass вывода.

Итак, я создал небольшой класс, который реализует интерфейс IAMWMBufferPassCallback из DirectShowLib:

 class IAMWMBufferPassCallbackImpl : IAMWMBufferPassCallback    
 {  
        private RecordingPlayer player;

        public IAMWMBufferPassCallbackImpl(RecordingPlayer player)
        {
            this.player = player;
        }

        public int Notify(INSSBuffer3 pNSSBuffer3, IPin pPin, long prtStart, long prtEnd)
        {
            if (player.bufferPin == pPin && !player.firstBufferHandled)
            {
                player.firstBufferHandled = true;

                //do stuff with the buffer....
            }

            return 0;
        }

}

Затем я получил интерфейс IAMWMBufferPass для требуемого вывода и передал экземпляр этого класса методу SetNotify:

bufferPassCallbackInterface = new IAMWMBufferPassCallbackImpl(this);

IAMWMBufferPass bPass = (IAMWMBufferPass)DSHelper.GetPin(pWMASFWriter, "Video Input 01");

hr = bPass.SetNotify(bufferPassCallbackInterface);
DsError.ThrowExceptionForHR(hr);  

Не выдается исключение, указывающее, что метод SetNotify завершился успешно.

Теперь проблема в том, что метод Notify в моем объекте обратного вызова никогда не вызывается. Запись видео без проблем, за исключением того факта, что обратный вызов не выполняется вообще.

Это проблема с тем, как я делаю взаимодействие?

Ответы [ 3 ]

0 голосов
/ 26 января 2010

То, как вы делаете взаимодействие, выглядит совершенно нормально. Я посмотрел документы MSDN, и похоже, что вы идете в правильном направлении, поэтому я не знаю, почему он не сделал обратный вызов.

Однако, как только вы сделаете это, сделав обратный вызов, вы можете обязательно вызвать Marshal.ReleaseComObject (pNSSBuffer3). Иногда образцы буферов не освобождаются для обработки, пока не будут удалены все другие ссылки. Так обстоит дело с SampleGrabber, поэтому может быть то же самое для этого.

0 голосов
/ 26 января 2010

Возможно, вам следует использовать делегата:

delegate int NotifyDelegate(INSSBuffer3 pNSSBuffer3, IPin pPin, long prtStart, long prtEnd);

void run(){
  bufferPassCallbackInterface = new IAMWMBufferPassCallbackImpl(this);

  IAMWMBufferPass bPass = (IAMWMBufferPass)DSHelper.GetPin(pWMASFWriter, "Video Input 01");
  NotifyDelegate d = new NotifyDelegate(bufferPassCallbackInterface.Notify);

  hr = bPass.SetNotify(d);
  DsError.ThrowExceptionForHR(hr);  
}

Однако я не совсем уверен, как вы реализуете неуправляемый интерфейс в управляемом классе. INSSBuffer3 * в C ++ напрямую не соотносится с новым INNSBuffer3 () в C #.

Edit:

В ответ на ваш комментарий функция SetNotify определяется как

HRESULT SetNotify(
  [in]  IAMWMBufferPassCallback *pCallback
);

Итак, требуется указатель на реализацию IAMWMBufferPassCallback.

MSDN говорит, что pCallback - это pCallback

Указатель на приложение Интерфейс IAMWMBufferPassCallback.

Делегат является (попыткой быть) управляемым эквивалентом указателя на IAMWMBufferPassCallback. Обратный вызов - это, как правило, метод, а не объект. Таким образом, передача экземпляра делегата должна работать для вас. Другой похожий пример - InternetSetStatusCallback , где вы передаете указатель на реализацию InternetStatusCallback .

Я бы попробовал, если это не сработает, почему бы не попробовать библиотеку, где кто-то уже проделал всю тяжелую работу? DirectShowNet может быть вариантом (я никогда не использовал его).

0 голосов
/ 25 января 2010

Я обычно работаю с делегатами для указателей на функции в небезопасном коде C #.
Единственная хитрость заключается в том, что вам нужно убедиться, что ссылка на делегат не собирается сборщиком мусора, поскольку ссылка в небезопасном коде не используется при подсчете ссылок внутри сборщика мусора. Таким образом, функция либо должна быть статической, либо объект, содержащий ссылку, нуждается в дополнительной искусственной ссылке для обеспечения ее доступности.
Это руководство по использованию делегатов в MSDN.

...