Асинхронные MFT

В этом разделе описывается асинхронная обработка данных для преобразований Media Foundation (MFT).

Примечание

Этот раздел относится к Windows 7 или более поздней версии.

 

Сведения об асинхронных MFT

Когда в Windows Vista появились MFT, API был разработан для синхронной обработки данных. В этой модели MFT всегда ожидает получения входных данных или ожидает получения выходных данных.

Рассмотрим типичный декодер видео. Чтобы получить декодированные кадры, клиент вызывает IMFTransform::P rocessOutput. Если декодер имеет достаточно данных для декодирования кадра, ProcessOutput блокирует, а MFT декодирует кадр. В противном случае ProcessOutput возвращает MF_E_TRANSFORM_NEED_MORE_INPUT, указывая, что клиент должен вызвать IMFTransform::P rocessInput.

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

В Windows 7 реализована асинхронная обработка для MFT на основе событий. В этой модели каждый раз, когда MFT требует ввода или имеет выходные данные, он отправляет событие клиенту.

Общие требования

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

Асинхронный MFT должен реализовывать следующие интерфейсы:

События

Асинхронный MFT использует следующие события, чтобы сообщить о состоянии обработки данных:

Событие Описание
METransformNeedInput Отправляется, когда MFT может принимать дополнительные входные данные.
METransformHaveOutput Отправляется, когда MFT имеет выходные данные.
METransformDrainComplete Отправляется по завершении операции очистки. См. раздел Очистка.
METransformMarker Отправляется, когда маркер является процессом. См. раздел Маркеры.

 

Эти события отправляются вне сети. Важно понимать разницу между событиями в диапазоне и внеполосными событиями в контексте MFT.

Оригинальная конструкция MFT поддерживает события в канале . Событие в канале содержит сведения о потоке данных, например сведения об изменении формата. Клиент отправляет события в MFT, вызывая IMFTransform::P rocessEvent. MFT может отправлять события в канале обратно клиенту в методе ProcessOutput . (В частности, события передаются в элементе pEventsструктуры MFT_OUTPUT_DATA_BUFFER .)

MFT отправляет внеполосные события через интерфейс IMFMediaEventGenerator следующим образом:

  1. MFT реализует интерфейс IMFMediaEventGenerator , как описано в разделе Генераторы событий мультимедиа.
  2. Клиент вызывает IUnknown::QueryInterface в MFT для интерфейса IMFMediaEventGenerator . Асинхронный MFT должен предоставлять этот интерфейс. Синхронные MFT не должны предоставлять этот интерфейс.
  3. Клиент вызывает IMFMediaEventGenerator::BeginGetEvent и IMFMediaEventGenerator::EndGetEvent для получения событий внешнего диапазона из MFT.

ProcessInput

Метод IMFTransform::P rocessInput изменяется следующим образом:

  1. При запуске потоковой передачи клиент отправляет MFT_MESSAGE_NOTIFY_START_OF_STREAM сообщение.
  2. Во время потоковой передачи MFT запрашивает данные, отправляя событие METransformNeedInput . Данные события являются идентификатором потока.
  3. Для каждого события METransformNeedInput клиент вызывает ProcessInput для указанного потока.
  4. В конце потоковой передачи клиент может вызвать ProcessMessage с сообщением MFT_MESSAGE_NOTIFY_END_OF_STREAM .

Примечания о реализации:

ProcessOutput

Метод IMFTransform::P rocessOutput изменяется следующим образом:

  1. Всякий раз, когда MFT имеет выходные данные, он отправляет событие METransformHaveOutput .
  2. Для каждого события METransformHaveOutput клиент вызывает ProcessOutput.

Примечания о реализации:

  • Если клиент вызывает ProcessOutput в любое другое время, метод возвращает E_UNEXPECTED.
  • Асинхронный MFT никогда не должен возвращать MF_E_TRANSFORM_NEED_MORE_INPUT из метода ProcessOutput . Если MFT требует дополнительных входных данных, он отправляет событие METransformNeedInput .

Слива

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

  1. Клиент отправляет сообщение MFT_MESSAGE_COMMAND_DRAIN .
  2. MFT продолжает отправлять события METransformHaveOutput , пока не будет больше данных для обработки. В течение этого времени он не отправляет события METransformNeedInput .
  3. После того как MFT отправляет последнее событие METransformHaveOutput , он отправляет событие METransformDrainComplete .

После завершения очистки MFT не отправляет другое событие METransformNeedInput , пока не получит MFT_MESSAGE_NOTIFY_START_OF_STREAM сообщение от клиента.

Промывки

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

MFT не отправляет другое событие METransformNeedInput , пока не получит сообщение MFT_MESSAGE_NOTIFY_START_OF_STREAM от клиента.

Маркеры

Клиент может пометить точку в потоке, отправив MFT_MESSAGE_COMMAND_MARKER сообщение. MFT отвечает следующим образом:

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

Например, предположим, что декодер имеет достаточно входных данных для создания четырех выходных выборок. Если клиент отправляет MFT_MESSAGE_COMMAND_MARKER сообщение, MFT будет ставить в очередь четыре события METransformHaveOutput (по одному для каждого выходного примера), за которым следует событие METransformMarker .

Сообщение маркера похоже на сообщение о утечке. Однако слив считается разрывом в потоке, а маркер — нет. Очистка и маркеры имеют следующие различия.

Слива:

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

Маркер:

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

Изменения формата

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

Атрибуты

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

attribute Описание
MF_TRANSFORM_ASYNC MFT должен задать для этого атрибута значение TRUE (1). Клиент может запросить этот атрибут, чтобы определить, является ли MFT асинхронным.
MF_TRANSFORM_ASYNC_UNLOCK
MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE MFT должен задать для этого атрибута значение TRUE (1). Клиент может предположить, что этот атрибут задан.

 

Разблокировка асинхронных MFT

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

Клиент вызывает IMFTransform::GetAttributes на MFT. Клиент запрашивает для этого атрибута MF_TRANSFORM_ASYNC . Для асинхронного MFT значение этого атрибута равно **TRUE**. Чтобы разблокировать MFT, клиент должен задать атрибуту MF_TRANSFORM_ASYNC_UNLOCK значение **TRUE**.

Пока клиент не разблокирует MFT, все методы IMFTransform должны возвращать MF_E_TRANSFORM_ASYNC_LOCKED, за следующими исключениями:

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

HRESULT UnlockAsyncMFT(IMFTransform *pMFT)
{
    IMFAttributes *pAttributes = NULL;

    HRESULT hr = hr = pMFT->GetAttributes(&pAttributes);

    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE);
        pAttributes->Release();
    }
    
    return hr;
}

Завершение работы MFT

Асинхронные MFT должны реализовывать интерфейс IMFShutdown .

  • Завершение работы. MFT должен завершить работу своей очереди событий. Если используется стандартная очередь событий, вызовите IMFMediaEventQueue::Shutdown. При необходимости MFT может освободить другие ресурсы. Клиент не должен использовать MFT после вызова завершения работы.
  • GetShutdownStatus: после вызова завершения работы MFT должен вернуть значение , MFSHUTDOWN_COMPLETED в параметре pStatus . Он не должен возвращать значение MFSHUTDOWN_INITIATED.

Регистрация и перечисление

Чтобы зарегистрировать асинхронный MFT, вызовите функцию MFTRegister и установите флаг MFT_ENUM_FLAG_ASYNCMFT в параметре Flags . (Ранее этот флаг был зарезервирован.)

Чтобы перечислить асинхронные MFT, вызовите функцию MFTEnumEx и установите флаг MFT_ENUM_FLAG_ASYNCMFT в параметре Flags . Для обеспечения обратной совместимости функция MFTEnum не перечисляет асинхронные MFT. В противном случае установка асинхронного MFT на компьютере пользователя может привести к прерыванию работы существующих приложений.

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