Поделиться через


Потоки потоковой передачи и приложений

[Функция, связанная с этой страницей DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngine, и аудио/ видео захвата в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать в новом коде MediaPlayer, IMFMediaEngine и аудио/видеозахват в Media Foundation вместо DirectShow, когда это возможно. Корпорация Майкрософт предлагает переписать существующий код, в котором используются устаревшие API, чтобы по возможности использовать новые API.]

Любое приложение DirectShow содержит по крайней мере два важных потока: поток приложения и один или несколько потоков потоковой передачи. Примеры доставляются в потоках потоковой передачи, а в потоке приложения происходят изменения состояния. Поток потоковой передачи main создается фильтром источника или средства синтаксического анализа. Другие фильтры могут создавать рабочие потоки, которые доставляют примеры, и они также считаются потоками потоковой передачи.

Некоторые методы вызываются в потоке приложения, а другие — в потоке потоковой передачи. Пример:

Наличие отдельного потока потоковой передачи позволяет передавать данные через граф, пока поток приложения ожидает ввода данных пользователем. Однако опасность нескольких потоков заключается в том, что фильтр может создавать ресурсы при приостановке (в потоке приложения), использовать их в методе потоковой передачи и уничтожать при остановке (также в потоке приложения). Если вы не будете осторожны, поток потоковой передачи может попытаться использовать ресурсы после их уничтожения. Решение заключается в защите ресурсов с помощью критически важных разделов и синхронизации методов потоковой передачи с изменениями состояния.

Фильтру требуется один критический раздел для защиты состояния фильтра. Класс CBaseFilter имеет переменную-член для этого критического раздела CBaseFilter::m_pLock. Этот критический раздел называется блокировкой фильтра. Кроме того, для каждого контактного ввода требуется критически важный раздел для защиты ресурсов, используемых потоком потоковой передачи. Эти критические разделы называются блокировками потоковой передачи; Их необходимо объявить в производном классе pin. Проще всего использовать класс CCritSec , который упаковывает объект Windows CRITICAL_SECTION и может быть заблокирован с помощью класса CAutoLock . Класс CCritSec также предоставляет некоторые полезные функции отладки. Дополнительные сведения см. в разделе Функции отладки критических разделов.

Когда фильтр останавливается или сбрасывается, он должен синхронизировать поток приложения с потоком потоковой передачи. Чтобы избежать взаимоблокировки, сначала необходимо разблокировать поток потоковой передачи, который может быть заблокирован по нескольким причинам:

  • Он ожидает получения примера в методе IMemAllocator::GetBuffer , так как используются все примеры распределителя.
  • Он ожидает возврата другого фильтра из метода потоковой передачи, например Receive.
  • Он ожидает в одном из собственных методов потоковой передачи, чтобы какой-то ресурс стал доступным.
  • Это фильтр отрисовщика, ожидающий времени презентации следующего примера.
  • Это фильтр отрисовщика, ожидающий внутри метода Receive во время приостановки.

Поэтому при остановке или очистке фильтра необходимо выполнить следующие действия:

  • Отпустите любой образец, который он держит по любой причине. Это разблокирует метод GetBuffer .
  • Возврат из любого метода потоковой передачи как можно быстрее. Если метод потоковой передачи ожидает ресурса, он должен немедленно прекратить ожидание.
  • Начните отклонять примеры в receive, чтобы поток потоковой передачи не получал доступ к дополнительным ресурсам. (Класс CBaseInputPin обрабатывает это автоматически.)
  • Метод Stop должен выводить из эксплуатации все распределители фильтра. (Класс CBaseInputPin обрабатывает это автоматически.)

Очистка и остановка выполняются в потоке приложения. Фильтр останавливается в ответ на метод IMediaControl::Stop . Диспетчер фильтров графов выдает команду stop в вышестоящий порядке, начиная с отрисовщиков и переходя назад к исходным фильтрам. Команда stop выполняется полностью внутри метода CBaseFilter::Stop фильтра. При возврате метода фильтр должен находиться в остановленном состоянии.

Очистка обычно происходит из-за команды seek. Команда очистки начинается из фильтра источника или средства синтаксического анализа и перемещается вниз по течению. Очистка выполняется в два этапа: метод IPin::BeginFlush сообщает фильтру, чтобы удалить все ожидающие и входящие данные; Метод IPin::EndFlush сигнализирует фильтру о повторном приеме данных. Очистка требует двух этапов, так как вызов BeginFlush находится в потоке приложения, во время которого поток потоковой передачи продолжает доставлять данные. Поэтому некоторые примеры могут поступать после вызова BeginFlush . Фильтр должен отменить их. Все образцы, поступающие после вызова EndFlush , гарантированно будут новыми и должны быть доставлены.

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

Примечание

Базовые классы CTransformFilter и CTransInPlaceFilter устраняют многие проблемы, описанные в этой статье. Если вы пишете фильтр преобразования и фильтр не ожидает событий внутри метода потоковой передачи или не удерживает примеры за пределами Receive, то этих базовых классов должно быть достаточно.