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


Потоки стриминга и приложения

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

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

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

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

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

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

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

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

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

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

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

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

Заметка

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