При остановке IMFSourceReader, как я могу убедиться, что OnReadSample больше не будет вызываться? - PullRequest
0 голосов
/ 17 января 2019

Я использую Media Framework SDK для захвата видео с камеры. Мой код основан на примере MFCaptureD3D . Мой код и этот пример используют IMFSourceReader для асинхронного чтения кадров с камеры. Для этого приложение предоставляет реализацию IMFSourceReaderCallback, чей OnReadSample вызывается из потока MFSDK с каждым доступным кадром.

Пример работает, за исключением того, что я не смог найти надежный способ остановки захвата камеры. В частности, даже после вызова Stop и Shutdown в исходном считывателе иногда может быть вызван обратный вызов OnReadSample. Если после вызова Stop и Shutdown приложение удаляет ресурсы, которые используются в OnReadSample, то OnReadSample завершится сбоем.

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

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Хотя ответы и комментарии, размещенные здесь, были полезны, они не были причиной проблемы в моем случае.

Фактическая проблема заключалась в том, что образец поступал после того, как я уничтожил объект обратного вызова. Я думал, что решил эту проблему, используя «флаг, мьютекс и переменную условия», как описано в моем комментарии, но эта реализация была неправильной. Решение, которое решило проблему, было следующим:
  1. Определите два 64-битных счетчика ReceiveSamples и requiredSamples. Кроме того, флаг "остановлено", мьютекс и переменная условия.
  2. После запуска заблокируйте мьютекс и установите счетчики на 0, а флаг остановки - на false. Затем вызовите sourceReader-> ReadSample, чтобы инициировать получение первого образца.
  3. В Stop, заблокируйте мьютекс, установите для остановленного flog значение true и используйте условную переменную, чтобы дождаться, пока receiveSamples == requiredSamples.
  4. В OnReadSample заблокируйте мьютекс, увеличьте счетчик receiveSamples, разблокируйте мьютекс и уведомите переменную условия.
  5. Непосредственно перед вызовом sourceReader-> ReadSample заблокировать мьютекс (если он еще не принадлежал), чтобы увеличить счетчик requiredSamples.

Я добавлю фрагмент кода, который вскоре это продемонстрирует

0 голосов
/ 17 января 2019

Поздний OnReadSample обратный вызов возможен из-за многопоточного характера приложения и таких вызовов, инициируемых из рабочих потоков. В отличие от других примеров, которые для краткости кода срезают углы в реализации объекта обратного вызова, MFCaptureD3D реализует обратный вызов для класса CPreview с обычным подсчетом ссылок. Может быть поздний CPreview::OnReadSample вызов, а затем за ним следует IMFSourceReaderCallback::Release вызов, который, как ожидается, удалит экземпляр CPreview (если вы не ссылаетесь на него для других нужд).

Сказав это,

  • убедитесь, что с вашим счетчиком ссылок и управлением интерфейсом все в порядке
  • остановить захват, как вы уже делаете
  • будьте готовы к редким поздним обратным вызовам
  • в вашем классе, который принимает обратные вызовы, вы можете добавить флаг, указывающий состояние завершения, и проверить его, чтобы он немедленно возвращался и ничего не делал, например, здесь в строке 189 ; когда вы останавливаете перехват, установите также этот флаг в вашем классе обратного вызова, чтобы игнорировать поздние вызовы
  • в случае позднего обратного вызова ваш класс обратного вызова все еще имеет ссылку на интерфейс COM из API; флаг помощника защитит вас от вредных действий
  • вы можете проверить освобождение COM-интерфейса и удаление объекта обратного вызова в случае, если вы хотите быть уверенным, что дальнейший обратный вызов не поступит, но я бы сказал, что с предложенным флагом вам не нужно делать это в качестве ресурсов будет освобожден точно, хотя возможно с небольшой задержкой, вызванной многопоточностью
...