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

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

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

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

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

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

Создание 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 для добавления дополнительных входных потоков или IMFTransform::D eleteInputStream для удаления входных потоков. (Невозможно добавить или удалить потоки вывода.)

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

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

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

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

  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. Для каждого выходного потока вызовите IMFTransform::SetOutputType , чтобы задать тип вывода. Тип носителя можно использовать на шаге 3 или тип, описывающий требуемый формат вывода.
  5. Если какие-либо входные потоки не имеют типа носителя, вернитесь к шагу 1.

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

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

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

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

  1. Вызовите IMFTransform::P rocessMessage с сообщением MFT_MESSAGE_NOTIFY_BEGIN_STREAMING. Это сообщение запрашивает MFT для выделения всех необходимых ресурсов во время потоковой передачи.
  2. ВызовИТЕ IMFTransform::P rocessInput по крайней мере на один входной поток для доставки входного образца в MFT.
  3. (Необязательно.) Вызовите IMFTransform::GetOutputStatus , чтобы запросить, может ли MFT создать выходной пример. Если метод возвращает S_OK, проверьте параметр pdwFlags . Если pdwFlags содержит флаг MFT_OUTPUT_STATUS_SAMPLE_READY , перейдите к шагу 4. Если pdwFlags равно нулю, вернитесь к шагу 2. Если метод возвращает E_NOTIMPL, перейдите к шагу 4.
  4. ВызовИТЕ IMFTransform::P rocessOutput, чтобы получить выходные данные.
    • Если метод возвращает 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 должен возвращать код ошибки, если это недопустимая операция. Короче говоря, MFT должны предполагать очень мало порядка операций, кроме того, что задокументировано в самих вызовах.

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

flow chart that leads from get stream identifiers through loops that set input types, get input, and process output

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

При необходимости 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. Он описан в разделе асинхронных MFT.

IMF2DBuffer

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

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

Очистка MFT

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

Чтобы очистить MFT, вызовите IMFTransform::P rocessMessage с сообщением 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 с одним входным и одним выходом можно использовать следующее общее правило:

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

Прерывания

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

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

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

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

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

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

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

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

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

Потоковая передача событий

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

Преобразования Media Foundation