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


Написание исходного фильтра для DirectShow

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

В этом разделе описывается написание настраиваемого фильтра источника для DirectShow.

Примечание

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

Модель потоковой передачи DirectShow

При написании фильтра источника важно понимать, что источник отправки — это не то же самое, что динамический источник. Динамический источник получает данные из какого-либо внешнего источника, например камеры или сетевого потока. Как правило, динамический источник не может управлять скоростью входящих данных. Если подчиненные фильтры не потребляют данные достаточно быстро, источнику потребуется удалить выборки.

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

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

Поток потоковой передачи запускает цикл со следующей структурой:

until (stopped)
  1. Get a media sample from the allocator.
  2. Fill the sample with data.
  3. Time stamp the sample. 
  4. Deliver the sample downstream.

Если примеры недоступны, шаг 1 блокируется до тех пор, пока пример не станет доступным. Шаг 4 также может блокировать; Например, он может блокироваться во время приостановки графа.

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

Использование CSource и CSourceStream

Базовые классы DirectShow включают два класса, поддерживающих источники push-уведомлений: CSource и CSourceStream.

  • CSource является базовым классом для фильтра и реализует интерфейс IBaseFilter .
  • CSourceStream является базовым классом для выходных контактов и реализует интерфейс IPin .

Выходные контакты

Фильтр источника может иметь несколько выходных контактов. В методе конструктора фильтра создайте один или несколько контактов, производных от CSourceStream (по одному контакту на поток вывода). Вам не нужно хранить указатели на контакты; контакты автоматически добавляются в фильтр при их создании.

Форматы выходных данных

Выходной контакт обрабатывает согласование формата с помощью следующих методов CSourceStream :

Метод Описание
GetMediaType Возвращает тип носителя из выходного закрепления.
Контакт должен предлагать по крайней мере один тип носителя, так как подчиненный фильтр может не предлагать никаких типов. В большинстве случаев подчиненным фильтром будет декодер или отрисовщик в зависимости от того, предоставляет ли исходный фильтр сжатые или несжатые данные. Фильтру отрисовщика обычно требуется полный тип носителя, содержащий все сведения о формате, необходимые для отрисовки потока. Для декодера объем сведений, необходимых для типа носителя, во многом зависит от формата кодирования.
CheckMediaType Проверяет, принимает ли выходной контакт заданный тип мультимедиа. Переопределение этого метода является необязательным в зависимости от способа реализации GetMediaType.

Метод GetMediaType перегружен:

  • GetMediaType (1) принимает один параметр, указатель на объект CMediaType .
  • GetMediaType (2) принимает переменную индекса и указатель на объект CMediaType .

Если выходной контакт исходного фильтра поддерживает только один формат мультимедиа, необходимо переопределить (1), чтобы инициализировать объект CMediaType с этим форматом. Оставьте реализацию по умолчанию (2), а также оставьте реализацию CheckMediaType по умолчанию.

Если закрепление поддерживает несколько форматов, переопределите (2). Инициализируйте объект CMediaType в соответствии со значением переменной индекса. Закрепление должно возвращать форматы в виде упорядоченного списка. В этом случае необходимо также переопределить CheckMediaType, чтобы проверка тип носителя в списке форматов.

Для несжатых форматов видео помните, что нижестоящий фильтр может предлагать форматы с различными значениями шага. Фильтр должен принимать любое допустимое значение шага. Дополнительные сведения см. в разделе BITMAPINFOHEADER.

Необходимо также переопределить метод CBaseOutputPin::D ecideBufferSize . Используйте этот метод, чтобы задать размер буферов выборки.

Потоковые операторы

Класс CSourceStream создает поток потоковой передачи для контакта. Процедура потока реализуется в методе CSourceStream::D oBufferProcessingLoop . Этот метод вызывает чисто виртуальный метод CSourceStream::FillBuffer , который должен переопределить производный класс. В этом методе закрепление заполняет буфер данными. Например, если фильтр доставляет несжатые видео, это место для рисования видеокадров.

Базовый класс автоматически запускает и останавливает цикл потока в нужное время, когда фильтр приостанавливается или останавливается. В этом случае класс CSourceStream вызывает некоторые методы для уведомления производного класса:

Эти методы можно переопределить, если необходимо добавить какую-либо специальную обработку. В противном случае реализации по умолчанию просто возвращают S_OK.

Ищут

Если у вас есть фильтр источника с одним выходным маркером, можно использовать класс CSourceSeeking в качестве отправной точки для реализации поиска. Наследуйте класс pin от CSourceStream и CSourceSeeking.

Примечание

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

Класс CSourceSeeking управляет скоростью воспроизведения, временем начала, временем остановки и длительностью. Производный класс должен задавать начальное время и длительность остановки. При изменении одного из этих значений вызывается метод CSourceSeeking::ChangeRate, CSourceSeeking::ChangeStart или CSourceSeeking::ChangeStop . Все методы являются чисто виртуальными методами. Производный класс закрепления переопределяет эти методы для выполнения следующих действий:

  1. Вызовите метод IPin::BeginFlush на подчиненном закреплении. Это приводит к тому, что подчиненные фильтры освобождают образцы, которые они хранят, и отклоняют новые примеры.
  2. Вызовите CSourceStream::Stop , чтобы остановить поток потоковой передачи. Исходный фильтр приостанавливает создание новых данных.
  3. Вызовите метод IPin::EndFlush на подчиненном закреплении. Это сигнализирует подчиненным фильтрам о приеме новых данных.
  4. Вызовите метод IPin::NewSegment с новым временем начала и остановки и скоростью.
  5. Задайте свойство прерывания для следующего примера.

Дополнительные сведения см. в разделе Поддержка поиска в исходном фильтре.

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

  • время начала примера = время затраченного времени / скорость воспроизведения
  • sample end time = sample start time + (time per frame /playback rate)

Где время, прошедшее — это время, прошедшее с момента запуска фильтра или последней команды поиска.

Форматы времени для поиска

По умолчанию команды seek находятся в единицах по 100 наносекунд. Фильтр источника может поддерживать дополнительные форматы времени, например поиск по номеру кадра. Каждый формат времени определяется идентификатором GUID; См. раздел Идентификаторы GUID формата времени.

Для поддержки дополнительных форматов времени необходимо реализовать следующие методы в выходном контакте:

Если приложение задает новый формат времени, все параметры позиции в методах IMediaSeeking интерпретируются с точки зрения нового формата времени. Например, если формат времени — кадры, метод IMediaSeeking::GetDuration должен возвращать длительность в кадрах.

На практике некоторые фильтры DirectShow поддерживают дополнительные форматы времени, и, как следствие, лишь немногие приложения DirectShow используют эту возможность.

Написание исходных фильтров