Асинхронные MFTs
В этом разделе описывается асинхронная обработка данных для преобразований Media Foundation (MFT).
Заметка
Этот раздел относится к Windows 7 или более поздней версии.
- об асинхронных MFT
- общие требования
- события
- ProcessInput
- ProcessOutput
- очистка
- Очистка
- маркеров
- изменения формата
- атрибутов
- разблокировки асинхронных MFT
- завершение работы MFT
- регистрация и перечисление
- связанные разделы
Сведения об асинхронных 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 следующим образом:
- MFT реализует интерфейс IMFMediaEventGenerator, как описано в генераторах событий мультимедиа.
- Клиент вызывает IUnknown::QueryInterface на MFT для интерфейсаIMFMediaEventGenerator. Асинхронный MFT должен предоставлять этот интерфейс. Синхронные MFT не должны предоставлять этот интерфейс.
- Клиент вызывает IMFMediaEventGenerator::BeginGetEvent и IMFMediaEventGenerator::EndGetEvent для получения исходящих событий от MFT.
ProcessInput
Метод IMFTransform::P rocessInput изменяется следующим образом:
- При запуске потоковой передачи клиент отправляет сообщение MFT_MESSAGE_NOTIFY_START_OF_STREAM.
- Во время потоковой передачи MFT запрашивает данные, отправляя событие METransformNeedInput. Данные события — это идентификатор потока.
- Для каждого события METransformNeedInput клиент вызывает ProcessInput для указанного потока.
- В конце потоковой передачи клиент может вызвать ProcessMessage с сообщением MFT_MESSAGE_NOTIFY_END_OF_STREAM.
Заметки о реализации:
- MFT не должен отправлять события METransformNeedInput, пока не получит сообщение MFT_MESSAGE_NOTIFY_START_OF_STREAM.
- Во время потоковой передачи MFT может отправлять события METransformNeedInput в любое время.
- MFT должен поддерживать количество ожидающих событий METransformNeedIn put. Любой вызов ProcessInput, который не соответствует событию METransformNeedInput, должен возвращать MF_E_NOTACCEPTING.
- Когда MFT получает сообщение MFT_MESSAGE_NOTIFY_END_OF_STREAM, оно сбрасывает количество ожидающих событий METransformNeedInput до нуля.
- MFT не должен отправлять события METransformNeedIn put после получения сообщения MFT_MESSAGE_NOTIFY_END_OF_STREAM.
- Если ProcessInput вызывается до MFT_MESSAGE_NOTIFY_START_OF_STREAM или после MFT_MESSAGE_NOTIFY_END_OF_STREAM, метод должен вернуть MF_E_NOTACCEPTING.
ProcessOutput
Метод IMFTransform::P rocessOutput изменяется следующим образом:
- Каждый раз, когда MFT имеет выходные данные, он отправляет событие METransformHaveOutput.
- Для каждого события METransformHaveOutput клиент вызывает ProcessOutput.
Заметки о реализации:
- Если клиент вызывает ProcessOutput в любое другое время, метод возвращает E_UNEXPECTED.
- Асинхронный MFT никогда не должен возвращать MF_E_TRANSFORM_NEED_MORE_INPUT из метода ProcessOutput. Если для MFT требуется больше входных данных, он отправляет событие METransformNeedInput.
Осушение
Очистка MFT приводит к тому, что MFT создает столько выходных данных, сколько он может от любых входных данных уже отправлен. Очистка асинхронного MFT работает следующим образом:
- Клиент отправляет сообщение MFT_MESSAGE_COMMAND_DRAIN.
- MFT продолжает отправлять события METransformHaveOutput, пока не будет обрабатываться больше данных. В настоящее время он не отправляет события METransformNeedInput.
- После отправки последнего события 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 отвечает следующим образом:
- MFT создает столько выходных примеров, сколько он может из существующих входных данных, отправляя событие METransformHaveOutput для каждого выходного примера.
- После создания всех выходных данных 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с следующими исключениями:
- МВФTransform::GetAttributes (все асинхронные MFT)
- МВФTransform::GetInputAvailableType (все асинхронные MFT)
- IMFTransform::GetOutputCurrentType (только кодировщики)
- IMFTransform::SetOutputType (только кодировщики)
- МВФTransform::GetStreamCount (все асинхронные MFT)
- МВФTransform::GetStreamIDs (все асинхронные MFT)
В следующем коде показано, как разблокировать асинхронный 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 на компьютере пользователя может нарушить существующие приложения.
Связанные разделы