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


Создание пользовательского источника мультимедиа

В этом разделе описывается реализация пользовательского источника мультимедиа в Microsoft Media Foundation. Он содержит следующие разделы:

Создание дескриптора презентации

Метод IMFMediaSource::CreatePresentationDescriptor возвращает копию дескриптора презентации источника. Чтобы создать дескриптор презентации, необходимо знать количество потоков в исходном содержимом и возможные форматы каждого потока. Для каждого потока создайте дескриптор потока следующим образом:

  1. Создайте массив типов носителей. Каждый тип мультимедиа в массиве представляет возможный формат потока. Дополнительные сведения о создании типов носителей см. в разделе Типы носителей.
  2. Вызовите MFCreateStreamDescriptor, чтобы создать дескриптор потока. Передайте массив типов носителей. Функция возвращает указатель IMFStreamDescriptor.
  3. Вызовите IMFStreamDescriptor::GetMediaTypeHandler, чтобы получить обработчик типов медиа потокового дескриптора.
  4. Вызовите IMFMediaTypeHandler::SetCurrentMediaType, чтобы задать формат потока по умолчанию. Используйте один из типов мультимедиа, созданных на шаге 1. Как правило, следует использовать формат наиболее высокого качества.
  5. При необходимости задайте атрибуты дескриптора потока. Список атрибутов, применяемых к дескрипторам потока, см. в разделе Атрибуты дескриптора Stream.

Теперь создайте дескриптор презентации:

  1. Вызовите MFCreatePresentationDescriptor и передайте массив дескрипторов потоков. Функция возвращает указатель IMFPresentationDescriptor.
  2. Выберите поток(и) по умолчанию, вызвав IMFPresentationDescriptor::SelectStream, чтобы выбрать один или несколько потоков. В конфигурации по умолчанию должен быть выбран хотя бы один поток.
  3. При необходимости задайте атрибуты дескриптора презентации. Список атрибутов, применяемых к дескрипторам потока, см. в разделе Атрибуты дескриптора презентации.

Вы должны создать дескриптор презентации один раз, либо при запуске, либо после того, как источник проанализировал достаточно исходных данных, чтобы определить содержимое. Метод CreatePresentationDescriptor должен возвращать копию дескриптора презентации. Чтобы создать копию, вызовите IMFPresentationDescriptor::Clone. При возврате копии клиент не изменяет состояние дескриптора исходной презентации, например атрибутов или выбора потока. Однако помните, что Клон создает поверхностную копию, поэтому клиент может потенциально изменить базовые дескрипторы потока.

Запуск источника мультимедиа

Метод IMFMediaSource::Start запускает источник мультимедиа или ищет новую позицию. Вызов команды Start приводит к поиску, если предыдущее состояние было "приостановлено" или "запущено", и указано новое время начала. В противном случае метод Start вызывает . Когда операция запуска завершится, отправьте следующие события.

  1. Отправьте событие MENewStream для каждого нового потока, то есть каждого потока, который ранее был не выбран, а теперь выбран. Данные события — это указатель на поток.
  2. Отправьте событие MEUpdatedStream для каждого потока, который был выбран ранее и остается выбранным. Данные события — это указатель на поток. (Не отправляйте событие для деизбираемых потоков.)
  3. Если источник ищет, отправьте событие MESourceSeeked. В противном случае отправьте событие MESourceStarted. Данные события — это указанное время начала в методе Start. Для события MESourceStarted, если время начала VT_EMPTY, задайте атрибут MF_EVENT_SOURCE_ACTUAL_START для события. Значение атрибута — фактическое время начала.
  4. Для каждого потока, если источник выполняет поиск, отправьте событие MEStreamSeeked. В противном случае отправьте событие MEStreamStarted. Данные события — это время начала. (Источник мультимедиа может поставить событие в очередь на поток, вызвав метод IMFMediaEventGenerator::QueueEvent.)

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

Формат времени для метода Start задан в параметре pguidTimeFormat. Стандартный формат времени, указанный GUID_NULL, равен 100-наносекундным единицам. Источник мультимедиа должен поддерживать этот формат времени.

Ищущий

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

Время начала, заданное в исходных событиях (MESourceStarted, MESourceSeeked, MEStreamStartedи MEStreamSeeked) — это запрошенное время начала (значение, заданное в методе Start), независимо от фактической позиции начала.

Например, предположим, что первые несколько кадров видеопотока имеют следующие характеристики:

Образец 1 2 3 4
Время 33 мс 66 мс 100 мс 133 msec
Ключевой кадр? Да Нет Нет Да

 

Если метод Start вызывается со значением 100 миллисекунд, источник должен выводить видео, начиная с кадра 1, который является первым ключевым кадром до этого времени. Событие начала по-прежнему будет отражать 100 миллисекунд в данных события.

Приостановка источника мультимедиа

Метод IMFMediaSource::Pause приостанавливает медиаисточник.

Пока источник приостановлен, поток может создавать новые образцы и хранить их в очереди данных, но не доставляет эти образцы. Ниже приведены некоторые исключения для этого правила:

  • Динамические источники должны удалять данные при приостановке.
  • Если источник получает данные из сети, он может приостановить сервер.

Если клиент вызывает IMFMediaStream::RequestSample во время приостановки источника, запрос также помещается в очередь, пока источник не будет запущен снова. Запросы не следует удалять.

Приостановка разрешена только из состояния начала. В противном случае должны вернуть MF_E_INVALID_STATE_TRANSITION.

Создание исходных данных

Media Foundation использует модель вытягивания, то есть потоки создают и предоставляют образцы в ответ на запросы из конвейера. Поток может доставлять образцы, когда источник мультимедиа запущен и поток выбран. Поток предоставляет данные только в том случае, если клиент запрашивает новый пример.

Примеры запросов

Клиент запрашивает новый пример путем вызова IMFMediaStream::RequestSample. Ниже приведена последовательность операций:

  1. Клиент вызывает IMFMediaStream::RequestSample. Аргумент — это указатель на необязательный маркер объект, который клиент использует для отслеживания запроса. Клиент внедряет токен. Маркеры должны предоставлять интерфейс IUnknown. Клиент также может передать указатель NULL вместо токена.

  2. Если клиент предоставил маркер, поток мультимедиа вызывает AddRef на маркере и помещает маркер в очередь с принципом «первым вошёл, первым вышел». Метод возвращается, а остальные шаги выполняются асинхронно.

  3. Когда доступны дополнительные данные, поток мультимедиа создает новый пример. (Этот шаг подробно описан в следующем разделе.)

  4. Поток мультимедиа извлекает первый токен из очереди.

  5. Если маркер не NULL, поток мультимедиа устанавливает атрибут MFSampleExtension_Token на образце медиа. Значение атрибута — это указатель на маркер.

  6. Поток мультимедиа передает событие MEMediaSample. Данные события — это указатель на интерфейс образца IMFSample.

  7. Если клиент предоставил токен, поток мультимедиа вызывает Release для объекта токена.

Если поток мультимедиа не может выполнить запрос requestSample клиента, он извлекает маркер из очереди и вызывает выпуска на маркере, но не отправляет событие MEMediaSample.

Клиент может использовать маркер для отслеживания состояния запроса. Когда клиент получает событие MEMediaSample, он может получить маркер из примера и сопоставить его с исходным запросом. Клиент также может использовать токен, чтобы определить, не отклонил ли источник мультимедиа запрос. Если счётчик ссылок токена падает до нуля и мультимедийный поток не отправляет событие MEMediaSample, это означает, что запрос был сброшен.

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

Поток отвечает за буферизацию данных, которые накапливаются между вызовами RequestSample.

Когда поток мультимедиа достигает конца потока, он отправляет событие MEEndOfStream после последнего примера. После завершения каждого потока источник мультимедиа отправляет событие MEEndOfPresentation. После того как медиа-поток отправляет событие MEEndOfStream, метод RequestSample возвращает MF_E_END_OF_STREAM до перезапуска источника.

Распределение образцов

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

Поток должен задать метку времени и длительность, если известно. Метка времени относительно источника. В большинстве случаев начало содержимого соответствует метке времени нулю. Например, если источник считывает из файла мультимедиа, в начале файла будет нулевая отметка времени.

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

Если скорость воспроизведения быстрее или медленнее 1.0, конвейер настраивает частоту часов презентации. Источник не регулирует метки времени на образцах.

Источник может задать дополнительные сведения о примере, задав атрибуты. См. список атрибутов-примеров в .

Пробелы в потоке

Если в потоке имеется разрыв значительной продолжительности, рекомендуется, чтобы поток отправил событие MEStreamTick. Это событие уведомляет клиента об отсутствии образца. Данные события — это метка времени отсутствующих примеров в единицах по 100 наносекунд (VT_I8). Это событие может избавить подчиненные компоненты от ожидания выборок, которые не придут. Поток может отправлять столько событий MEStreamTick, сколько необходимо для охвата пробела в потоке.

Завершение работы источника мультимедиа

Когда клиент закончил использование медиаисточника, он вызывает IMFMediaSource::Shutdown. В этом методе источник мультимедиа должен разбить все циклические счетчики ссылок. Как правило, между источником мультимедиа и потоками мультимедиа будут циклические ссылки.

Если вы используете очередь событий для реализации IMFMediaEventGenerator, вызовите IMFMediaEventQueue::Shutdown для очереди событий. Этот метод завершает работу очереди обработки событий и сигнализирует всякому вызывающему, который в настоящее время ожидает события.

После завершения работы все методы источника возвращают MF_E_SHUTDOWN, за исключением методов IUnknown.

Активные источники

Начиная с Windows 7 Media Foundation автоматически поддерживает устройства записи аудио и видео. Для видео устройство должно предоставить миникодрайвер потоковой передачи ядра (KS) в категории видеозахвата. Media Foundation использует путь PnP для перечисления устройства. Для звука Media Foundation использует API мультимедийного устройства Windows (MMDevice) для перечисления конечных точек звука. Если устройство соответствует этим критериям, не требуется реализовать пользовательский источник мультимедиа.

Однако может потребоваться реализовать пользовательский источник мультимедиа для другого типа устройства или другого динамического источника данных. Существует лишь несколько различий между динамическим источником и другими источниками мультимедиа:

  • В методе IMFMediaSource::GetCharacteristics необходимо возвращать флаг MFMEDIASOURCE_IS_LIVE.
  • Первый пример должен иметь метку времени с нулевым значением.
  • События и состояния потоковой передачи обрабатываются так же, как источники мультимедиа, за исключением приостановленного состояния.
  • При приостановке не помещайте примеры в очередь. Удалите все данные, созданные при приостановке.
  • Живые источники обычно не поддерживают поиск, воспроизведение в обратном направлении или контроль скорости.

медиа источники

Учебное пособие: Написание пользовательского мультимедийного источника