Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Фреймворк GStreamer. Руководство разработчика плагинов. Перемещение в мультимедийном потоке, навигация и другие действия

Оригинал: GStreamer Plugin Writer's Guide
Авторы: Richard John Boulton, Erik Walthinsen, Steve Baker, Leif Johnson, Ronald S. Bultje, Stefan Kost, Tim-Philipp Muller, Wim Taymans
Дата публикации: 19 июля 2014 г.
Перевод: А.Панин
Дата перевода: 28 июля 2014 г.

Глава 17. Перемещение в мультимедийном потоке, навигация и другие действия

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

17.1. События, передаваемые по направлению конвейера

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

События могут передаваться по направлению конвейера двумя способами: они могут быть как внутириполосными (упакованными в поток данных посредством сериализации), так и внеполосными (передающимися в пределах конвейера в неизменном виде, возможно не в том же программном потоке, в котором осуществляется обработка буферов с данными мультимедийного потока, независимо от буферов мультимедийных данных, обрабатываемых и накапливаемых в рамках конвейера). Наиболее часто встречающиеся события, передаваемые по направлению конвейера (SEGMENT, CAPS, TAG, EOS), подвергаются сериализации и передаются вместе с буферами данных мультимедийного потока.

Ниже приведен пример реализации типичной функции обработки событий:

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

Если же ваш элемент использует петлевую схему, вы можете как использовать функцию обработки событий на уровне входной точки соединения, так и не использовать ее (ведь ваш элемент управляет работой конвейера и, следовательно, заранее получает информацию о продолжительности мультимедийного потока или получает уведомления, обрабатывая возвращаемые функцией gst_pad_pull_range () значения в процессе обработки мультимедийного потока). В некоторых случаях использующий петлевую схему элемент может принимать события от элементов, расположенных против направления конвейера (примерами могут служить декодеры аудиопотоков в случае расположения перед ними элементов демультиплексоров id3demux или apedemux или демультиплексоры, получающие данные от элементов для ввода данных, которые передают дополнительную информацию о мультимедийном потоке с помощью специальных событий точно также, как это делают элементы для ввода данных с DVD).

17.2. События, передаваемые против направления конвейера

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

Наиболее часто встречающимися событиями, передаваемыми против направления конвейера, являются события перемещения в мультимедийном потоке, события с информацией о качестве сервиса (Quality-of-Service, QoS) и события повторной настройки элементов.

Событие может быть отправлено против направления конвейера с помощью функции gst_pad_send_event (). Эта функция просто вызывает стандартный обработчик событий соответствующей точки соединения. Стандартным обработчиком событий точек соединения является функция gst_pad_event_default(), которая в общем случае отправляет событие связанной с использованием внутренних механизмов точке соединения соседнего элемента. Таким образом, отправляемые против направления конвейера события всегда попадают на выходную точку соединения вашего элемента и обрабатываются стандартным обработчиком событий за исключением тех случаев, когда вы перекрываете этот обработчик событий для того, чтобы обрабатывать события самостоятельно. Существуют особые случаи, когда вам придется сделать это:
  • Ваш элемент может иметь множество входных точек соединения. В этом случае вам придется решить, через какую из входных точек соединения вы будете передавать событие (конечно же, при условии, что не требуется передавать событие через все точки соединения).
  • Вы можете предпочесть локальную обработку события. Например, вы можете предпочесть преобразование события навигации перед передачей его расположенным против направления конвейера элементам или обработку события с информацией о качестве сервиса (QoS).
Механизм обработки событий, который вы используете в рамках функции обработки событий, не имеет особого значения, но существуют важные правила, которые вы должны строго соблюдать, ведь в случае некорректной реализации обработчика событий в рамках одного элемента, будет нарушена работа механизма обработки событий в рамках всего конвейера. Упомянутые правила:
  • Всегда обрабатывайте события, которые вы не планируете обрабатывать, с помощью стандартного метода gst_pad_event_default(). Этот метод передаст или отбросит событие в зависимости от его типа.
  • В том случае, если вы генерируете какое-либо новое событие на основе принятого события, не забудьте вызвать функцию gst_event_unref() для удаления ссылки на принятое событие.
  • Функция обработки событий должна возвращать логическое значение TRUE или FALSE, указывающее на то, было ли обработано событие или нет. Никогда просто не возвращайте значение TRUE/FALSE из этой функции обработки событий, если вы не уверены в том, что была осуществлена обработка события.
  • Помните о том, что обработчик событий может быть вызван из программного потока, отличного от программного потока, предназначенного для обработки мультимедийного потока, поэтому следует убедиться в том, вы установили соответствующие блокировки везде, где это необходимо.

17.3. Все события

В данном разделе приведен список всех объявленных событий, которые используются в рамках фреймворка на данный момент с информацией о том, как они должны быть использованы/интерпретированы. Вы можете проверить тип определенного события с помощью макроса GST_EVENT_TYPE (а в том случае, если вам нужна строка для отладки, вы можете использовать макрос GST_EVENT_TYPE_NAME).

Далее мы будем обсуждать следующие события:

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

17.3.1. Событие начала мультимедийного потока

Работа над описанием данного события пока не начата.

17.3.2.Событие с информацией о возможностях

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

17.3.3. Событие с информацией о сегменте мультимедийного потока

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

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

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

Событие с информацией о сегменте данных мультимедийного потока создается с помощью функции gst_event_new_segment (). Обратитесь к описанию API и документации по проектированию фреймворка для ознакомления с информацией о его параметрах.

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

17.3.4. Событие с информацией о тэгах (метаданными)

События с информацией о тэгах отправляются по направлению конвейера для указания на то, что из потока данных были извлечены значения тэгов. На данный момент это событие используется для сохранения тэгов в процессе перекодирования мультимедийного потока из одного формата в другой. Тэги подробно обсуждаются в Главе 22, "Тэги (метаданные и информация о потоке)". Большинству элементов следует просто передавать данное событие дальше по конвейеру путем вызова функции gst_pad_event_default ().

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

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

17.3.5. Событие окончания мультимедийного потока (EOS)

События окончания мультимедийного потока отправляются тогда, когда отправляемый элементом поток данных заканчивается. Элемент, принимающий это событие (ввиду того, что он принимает событие от элемента, расположенного против направления конвейера, для приема используется входная точка соединения) в общем случае должен обработать все буферизованные данные (если такие имеются), после чего отправить событие следующему находящемуся по направлению конвейера элементу. Функция gst_pad_event_default () самостоятельно позаботится о выполнении описанных действий, поэтому большая часть элементов не должна поддерживать данное событие. Исключениями из этого правила являются элементы, которые должны непосредственно освобождать ресурсы при достижении окончания мультимедийного потока, а также элементы, работающие по схеме N-к-1. Учтите, что сам мультимедийный поток не является ресурсом, который должен быть освобожден при получении события окончания потока! Приложения должны иметь возможность перехода назад к определенной позиции в мультимедийном потоке перед точкой его окончания для продолжения воспроизведения.

Событие окончания мультимедийного потока (EOS) не имеет свойств, что делает его одним из самых простых событий в рамках фреймворка GStreamer. Оно создается с помощью функции gst_event_new_eos().

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

17.3.6. Событие с данными из таблицы содержания DVD

Работа над описанием данного события пока не начата.

17.3.7. Событие разрыва мультимедийного потока

Работа над описанием данного события пока не начата.

17.3.8. Событие начала опустошения буферов

Событие начала опустошения буферов отправляется по направлению конвейера (при работе в режиме передачи) или против направления конвейера (при работе в режиме заполнения) в том случае, если все буферы и кэши в рамках конвейера должны быть опустошены. Например, при приеме этого события элементы "очередей" должны будут опустошить свои внутренние списки буферов. При приеме этого же события элементы вывода данных в файлы (например, элемент "filesink") должны будут записать содержимое реализованного на уровне ядра операционной системы дискового кэша на диск (с помощью функции fdatasync () или fflush () стандартной библиотеки). В нормальных условиях элементы, принимающие это событие, должны просто отправить его дальше по конвейеру, так как большинство элементов фильтров или аналогичных фильтрам элементов не имеет внутреннего кэша для хранения данных. Функция gst_pad_event_default () выполняет именно эту операцию, поэтому при обработке событий большинства элементов достаточно передать событие дальше по конвейеру с помощью стандартного обработчика событий.

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

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

17.3.9. Событие окончания опустошения буферов

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

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

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

17.3.10. Событие с информацией о качестве сервиса (QoS)

Событие с информацией о качестве сервиса содержит отчет о текущей производительности механизма обработки мультимедийного потока, измеряемой в реальном времени. Обратитесь к Главе 19, "Качество сервиса (QoS)" для получения дополнительной информации.

17.3.11. Событие с запросом перемещения в мультимедийном потоке

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

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

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

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

17.3.12. Событие навигации

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

Вся эта информация сохраняется в структуре события, которая может быть получена с помощью функции gst_event_get_structure ().

Рассмотрите код плагина navigationevent из пакета gst-plugins-good для получения представления о том, как следует извлекать данные навигации из этого события.


Следующий раздел : Таймеры.