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


Базовая модель обработки MFT

В этом разделе описывается, как клиент использует преобразование Media Foundation (MFT) для обработки данных. клиент — это любой объект, который напрямую вызывает методы в MFT. Это может быть приложение или система Media Foundation.

Ознакомьтесь с этой статьей, если вы:

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

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

Базовая модель обработки

Создайте MFT

Существует несколько способов создания MFT:

  • Вызовите функцию MFTEnum.
  • Вызовите функцию MFTEnumEx.
  • Если вы уже знаете CLSID для MFT, просто вызовите CoCreateInstance.

Некоторые MFTы могут предоставлять другие параметры, такие как специализированная функция создания.

Получение идентификаторов потока

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

Некоторые MFT позволяют клиенту добавлять или удалять входные потоки. Во время потоковой передачи MFT может добавлять или удалять выходные потоки. (Клиент не может добавлять или удалять потоки вывода.)

  1. (Необязательно.) Вызовите IMFTransform::GetStreamLimits, чтобы получить минимальное и максимальное количество потоков, которые может поддерживать MFT. Если минимальное и максимальное значение совпадают, MFT имеет фиксированное количество потоков.
  2. Вызовите IMFTransform::GetStreamCount, чтобы получить начальное количество потоков.
  3. Вызовите IMFTransform::GetStreamIDs, чтобы получить идентификаторы потока. Если этот метод возвращает E_NOTIMPL, это означает, что MFT имеет фиксированное количество потоков, а идентификаторы потоков являются последовательными и начинаются с нуля.
  4. (Необязательно.) Если MFT не имеет фиксированного количества потоков, вызовите IMFTransform::AddInputStreams для добавления дополнительных входных потоков или МВФTransform::D eleteInputStream для удаления входных потоков. (Нельзя добавлять или удалять потоки вывода.)

Настройка типов носителей

Перед обработкой данных MFT клиент должен задать типы носителей для каждого потока MFT. MFT может потребовать, чтобы клиент установил типы входных данных перед настройкой типов выходных данных или может потребовать обратного порядка (типы выходных данных сначала). Некоторые MFT не имеют требования к заказу.

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

Чтобы задать типы носителей, сделайте следующее:

  1. (Необязательно.) Для каждого входного потока вызовите IMFTransform::GetInputAvailableType, чтобы получить список предпочтительных типов для этого потока.
    • Если этот метод возвращает MF_E_TRANSFORM_TYPE_NOT_SET, необходимо сначала задать типы выходных данных; перейдите к шагу 3.
    • Если метод возвращает E_NOTIMPL, MFT не имеет списка предпочтительных типов входных данных; перейдите к шагу 2.
  2. Для каждого входного потока вызовите IMFTransform::SetInputType, чтобы задать тип ввода. Вы можете использовать тип носителя из шага 1 или тип, описывающий входные данные. Если любой поток возвращает MF_E_TRANSFORM_TYPE_NOT_SET, перейдите к шагу 3.
  3. (Необязательно.) Для каждого выходного потока вызовите IMFTransform::GetOutputAvailableType, чтобы получить список предпочтительных типов для этого потока.
    • Если этот метод возвращает MF_E_TRANSFORM_TYPE_NOT_SET, необходимо сначала задать типы входных данных; вернитесь к шагу 1.
    • Если любой поток возвращает E_NOTIMPL, MFT не содержит список предпочтительных типов выходных данных; перейдите к шагу 4.
  4. Для каждого выходного потока вызовите МВФTransform::SetOutputType, чтобы задать тип вывода. Можно использовать тип носителя из шага 3 или тип, описывающий требуемый формат выходных данных.
  5. Если входные потоки не имеют типа носителя, вернитесь к шагу 1.

Получение требований к буферу

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

Обработка данных

MFT предназначен для надежного компьютера состояния. Он не выполняет никаких обратных вызовов к клиенту.

  1. Вызовите МВФTransform::ProcessMessage с сообщением MFT_MESSAGE_NOTIFY_BEGIN_STREAMING. Это сообщение просит MFT выделить необходимые ресурсы во время стриминга.
  2. Вызовите IMFTransform::ProcessInput по крайней мере на один из входных потоков, чтобы доставить входной образец в MFT.
  3. (Необязательно.) Вызовите IMFTransform::GetOutputStatus, чтобы запросить, может ли MFT создать выходной пример. Если метод возвращает S_OK, проверьте параметр pdwFlags. Если pdwFlags содержит флаг MFT_OUTPUT_STATUS_SAMPLE_READY, перейдите к шагу 4. Если pdwFlags равно нулю, вернитесь к шагу 2. Если метод возвращает E_NOTIMPL, перейдите к шагу 4.
  4. Чтобы получить выходные данные, вызовите IMFTransform::ProcessOutput.
    • Если метод возвращает MF_E_TRANSFORM_NEED_MORE_INPUT, это означает, что MFT требует больше входных данных; вернитесь к шагу 2.
    • Если метод возвращает MF_E_TRANSFORM_STREAM_CHANGE, это означает, что количество выходных потоков изменилось или формат выходных данных изменился. Клиенту может потребоваться запросить новые идентификаторы потока или задать новые типы носителей. Дополнительные сведения см. в документации для ProcessOutput.
  5. Если для обработки по-прежнему есть входные данные, перейдите к шагу 2. Если MFT использовал все доступные входные данные, перейдите к шагу 6.
  6. Вызов ProcessMessage с сообщением MFT_MESSAGE_NOTIFY_END_OF_STREAM.
  7. Вызов ProcessMessage с использованием сообщения MFT_MESSAGE_COMMAND_DRAIN.
  8. Вызовите ProcessOutput, чтобы получить оставшиеся выходные данные. Повторите этот шаг, пока метод не возвращает MF_E_TRANSFORM_NEED_MORE_INPUT. Это возвращаемое значение сигнализирует о том, что все выходные данные были удалены из MFT. (Не рассматривайте это как условие ошибки.)

Последовательность, описанная здесь, сохраняет как можно меньше данных в MFT. После каждого вызова ProcessInputклиент пытается получить выходные данные. Для создания одного выходного примера может потребоваться несколько входных примеров, или один входной пример может создать несколько выходных примеров. Оптимальное поведение клиента заключается в том, чтобы извлечь выходные образцы из MFT, пока MFT не требует больше входных данных.

Однако MFT должен иметь возможность обрабатывать другой порядок вызовов методов клиентом. Например, клиент может просто чередовать вызовы ProcessInput и ProcessOutput. MFT должен ограничивать количество входных данных, которые он получает, возвращая MF_E_NOTACCEPTING от ProcessInput всякий раз, когда есть выходные данные для вывода.

Порядок вызовов методов, описанных здесь, не является единственной допустимой последовательностью событий. Например, шаги 3 и 4 предполагают, что клиент начинается с типов входных данных, а затем пытается использовать типы выходных данных. Клиент также может изменить этот порядок и начать с типов выходных данных. В любом случае, если MFT требует противоположного порядка, он должен вернуть код ошибки MF_E_TRANSFORM_TYPE_NOT_SET.

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

На следующей схеме показана блок-схема процедур, описанных в этом разделе.

блок-диаграмме, которая ведет от получения идентификаторов потока через циклы, которые задают типы входных данных, получают входные данные и обрабатывают выходные данные

Расширения базовой модели

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

  • Ленивые потоки чтения Если метод IMFTransform::GetOutputStreamInfo возвращает флаг MFT_OUTPUT_STREAM_LAZY_READ для выходного потока, клиент не должен собирать данные из этого выходного потока. MFT продолжает принимать входные данные, и в какой-то момент MFT отбрасывает выходные данные из этого потока. Если все выходные потоки имеют этот флаг, MFT никогда не откажется принимать входные данные. Примером может быть преобразование визуализации, когда клиент получает выходные данные только в том случае, если он имеет резервные циклы ЦП для рисования визуализации.
  • Отбрасываемые потоки. Если метод GetOutputStreamInfo возвращает флаг MFT_OUTPUT_STREAM_DISCARDABLE для выходного потока, клиент может запросить MFT отменить выходные данные, но MFT не будет удалять выходные данные, если не запрашивается. Когда MFT достигает максимального входного буфера, клиент должен либо собирать некоторые выходные данные, либо запросить MFT отказаться от выходных данных.
  • Необязательные потоки. Если метод getOutputStreamInfo возвращает флаг MFT_OUTPUT_STREAM_OPTIONAL для выходного потока или метод IMFTransform::GetInputStreamInfo возвращает флаг MFT_INPUT_STREAM_OPTIONAL входного потока, этот поток необязателен. Клиенту не нужно задавать тип носителя в потоке. Если клиент не задает тип, поток данных может быть не выбран. Выходной поток, который не выбран, не создает образцы, и клиент не обеспечивает поток буфером при вызове ProcessOutput. Выбранный входной поток не принимает входные данные. MFT может пометить все входные и выходные потоки как необязательные. Однако ожидается, что для работы MFT необходимо выбрать по крайней мере один вход и один выход.
  • Асинхронная обработка. Модель асинхронной обработки появилась в Windows 7. Он описан в разделе асинхронных MFTs.

IMF2DBuffer

Если MFT обрабатывает несжатые видеоданные, он должен использовать интерфейс IMF2DBuffer для управления образцами данных буфера. Чтобы получить этот интерфейс, запросите интерфейс IMFMediaBuffer для любого входного или выходного буфера. Не использование этого интерфейса, когда он доступен, может привести к дополнительным копиям буфера. Чтобы правильно использовать этот интерфейс, преобразование не должно блокировать буфер с помощью интерфейса IMFMediaBuffer, если доступен интерфейс IMF2DBuffer.

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

Очистка MFT

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

Чтобы очистить MFT, вызовите IMFTransform::ProcessMessage с сообщением MFT_MESSAGE_COMMAND_FLUSH.

Очистка MFT

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

  1. Вызвать ProcessMessage с сообщением MFT_MESSAGE_COMMAND_DRAIN. Это сообщение уведомляет MFT о том, что он должен выдавать максимально возможное количество выходных данных из входных данных, которые уже поступили.
  2. Вызовите ProcessOutput, чтобы получить выходные данные, пока метод не вернёт MF_E_TRANSFORM_NEED_MORE_INPUT.

Пока MFT очищается, он не будет принимать новые входные данные.

Пример атрибутов

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

  • Если MFT возвращает VARIANT_TRUE для свойства MFPKEY_EXATTRIBUTE_SUPPORTED, MFT должен скопировать атрибуты.
  • Если свойство MFPKEY_EXATTRIBUTE_SUPPORTED либо равно VARIANT_FALSE, либо не задано, клиент должен скопировать атрибуты.

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

  • Если каждый входной пример создает ровно один выходной пример, можно разрешить клиенту копировать атрибуты. Оставьте свойство MFPKEY_EXATTRIBUTE_SUPPORTED незаданным.
  • Если между входными выборками и выходными примерами нет единого соответствия, MFT должен определить правильные атрибуты для выходных выборок. Задайте для свойства MFPKEY_EXATTRIBUTE_SUPPORTED значение VARIANT_TRUE.

Разрывы

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

Некоторые преобразования, особенно те, которые обрабатывают несжатые данные, такие как эффекты аудио и видео, должны игнорировать разрывы при обработке входных данных. Эти MFT обычно предназначены для обработки непрерывных данных и должны обрабатывать любые данные, которые они получают как непрерывные, даже после прекращения.

Если MFT игнорирует разрыв входных данных, он по-прежнему должен задать флаг разрыва для выходного образца, если выходной образец имеет ту же метку времени, что и входной образец. Если выходный образец имеет другую метку времени, однако MFT не должен распространять разрыв. (Например, это может быть в некоторых звуковых ресэмплерах.) Прерывность в неправильном месте в потоке хуже, чем её отсутствие.

Большинство декодаторов не могут игнорировать прерывность, так как прерывность влияет на интерпретацию следующего примера. Любая технология кодирования, использующая сжатие между кадрами, например MPEG-2, попадает в эту категорию. Некоторые схемы кодирования используют только сжатие внутри кадра, например DV и MJPEG. Эти декодеры могут безопасно игнорировать разрывы.

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

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

Изменения динамического формата

Форматы могут изменяться во время потоковой передачи. Например, пропорции могут измениться в середине видеопотока.

Дополнительные сведения о том, как изменения потока обрабатываются MFT, см. в обработке изменений потока.

Трансляция событий

Чтобы отправить событие в MFT, вызовите IMFTransform::ProcessEvent. Если метод возвращает MF_S_TRANSFORM_DO_NOT_PROPAGATE_EVENT, MFT передаст событие обратно вызывающему, когда в дальнейшем будет вызван метод ProcessOutput. Если метод возвращает любое другое значение HRESULT, MFT не вернет событие клиенту в ProcessOutput. В этом случае клиент несет ответственность за распространение события вниз по следующему компоненту в конвейере, если применимо. Дополнительные сведения см. в разделе IMFTransform::ProcessOutput.

Media Foundation преобразуется