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


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

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

Заметка

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

 

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

При появлении MFT в Windows Vista 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. После отправки последнего события METransformHaveOutput MFT он отправляет событие 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. Это событие должно быть отправлено после всех событий METransformHaveOut put.

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

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

Осушение:

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

Маркер:

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

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

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

Атрибуты

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

Атрибут Описание
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

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

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

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

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

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

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