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

UnixForum





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

Фреймворк GStreamer. Руководство разработчика приложений. Манипуляции с конвейером

Оригинал: GStreamer Application Development Manual
Авторы: Wim Taymans, Steve Baker, Andy Wingo, Ronald S. Bultje, Stefan Kost
Дата публикации: 21 мая 2014 г.
Перевод: А.Панин
Дата перевода: 22 июня 2014 г.

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

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

19.1. Использование зондов

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

Зонд может уведомлять вас о следующей активности точек соединения:
  • Отправка или прием данных с использованием буфера. Вам придется указать идентификатор GST_PAD_PROBE_TYPE_BUFFER при регистрации зонда. Ввиду того, что работа точки соединения может планироваться различным образом, с помощью необязательного флага GST_PAD_PROBE_TYPE_PUSH или GST_PAD_PROBE_TYPE_PULL может быть также указан режим планирования работы точки соединения, который вас интересует.
    Вы можете использовать этот зонд для исследования, модификации и уничтожения данных буфера. Обратитесь к разделу под названием "Зонды для работы с данными" для получения дополнительной информации.
  • Отправка списка буферов. Используйте идентификатор GST_PAD_PROBE_TYPE_BUFFER_LIST при регистрации зонда.
  • Передача события посредством точки соединения. Используйте идентификаторы GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM и GST_PAD_PROBE_TYPE_EVENT_UPSTREAM для выбора событий, передаваемых вперед или назад по конвейеру. Также существует вспомогательный флаг GST_PAD_PROBE_TYPE_EVENT_BOTH для уведомления о событиях, передающихся как вперед, так и назад по конвейеру. По умолчанию события опустошения буферов не приводят к генерации уведомлений. Вам придется явно использовать идентификатор GST_PAD_PROBE_TYPE_EVENT_FLUSH для активации функции обратного вызова в моменты опустошения буферов. Уведомления о событиях обычно отправляются только в режиме заполнения.
    Вы можете использовать зонд данного типа для исследования, модификации и удаления события.
  • Передача запроса посредством точки соединения. Используйте идентификаторы GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM и GST_PAD_PROBE_TYPE_QUERY_UPSTREAM для выбора событий, передающихся вперед и назад по конвейеру соответственно. Вспомогательный флаг GST_PAD_PROBE_TYPE_QUERY_BOTH также может использоваться для выбора событий, передающихся по обоим направлениям. Зонды для отслеживания запросов будут отправлять по два уведомления: одно в момент передачи запроса вперед или назад по конвейеру и одно при возврате результата отправителю. Этап передачи запроса или возврата результата для активации функции обратного вызова может быть выбран с помощью идентификаторов GST_PAD_PROBE_TYPE_PUSH и GST_PAD_PROBE_TYPE_PULL соответственно.
    Вы можете использовать зонд данного типа для исследования или модификации запроса. Также вы можете ответить на запрос в рамках функции обратного вызова зонда, разместив результирующее значение в структуре запроса и вернув значение GST_PAD_PROBE_DROP при выходе из функции обратного вызова.
  • В дополнение приему уведомлений о передаче данных, вы можете запросить у зонда блокировку потока данных при возврате из функции обратного вызова. Зонд этого типа называется блокирующим зондом и активируется при использовании идентификатора GST_PAD_PROBE_TYPE_BLOCK. Вы можете использовать упомянутый идентификатор совместно с другими идентификаторами для блокировки потока данных исключительно в условиях определенной активности. Точка соединения снова разблокируется в том случае, если вы удалите зонд или вернете значение GST_PAD_PROBE_REMOVE из функции обратного вызова. Вы можете осуществить передачу исключительно текущего заблокированного фрагмента потока данных, вернув значение GST_PAD_PROBE_PASS из функции обратного вызова, причем точка соединения снова заблокируется при поступлении следующего фрагмента потока данных.
    Блокирующие зонды используются для временной блокировки точек соединения в том случае, если эти точки не связаны с другими точками или в том случае, если вы хотите отсоединить эти точки. В том случае, если передача данных не остановлена, конвейер перейдет в состояние ошибки при передаче данных на несвязанную точку соединения. Мы познакомимся с примером использования блокирующих зондов в процессе частичной подготовки конвейера к работе. Также следует обратиться к разделу под названием "Проигрывание фрагмента мультимедийного файла" для получения дополнительной информации.
  • Отсутствие активности точки соединения. Вы можете установить зонд данного типа с помощью идентификатора GST_PAD_PROBE_TYPE_IDLE. Также вы можете использовать идентификаторы GST_PAD_PROBE_TYPE_PUSH и/или GST_PAD_PROBE_TYPE_PULL для того, чтобы получать уведомления в зависимости от режима планирования работы точки соединения. Зонд типа IDLE также является блокирующим зондом, который не позволит любым данным пересечь текущую точку соединения в течение промежутка времени, пока зонд типа IDLE установлен.
    Вы можете использовать зонды бездействия для динамического повторного связывания точки соединения. Мы познакомимся с примером использования зондов бездействия в процессе замены элемента из конвейера. Также следует обратиться к разделу "Динамическое изменение конвейера" для получения дополнительной информации.

19.1.1. Зонды для работы с данными

Зонды для работы с данными позволяют получать уведомления при передаче данных через точку соединения. При добавлении точки соединения следует использовать идентификатор GST_PAD_PROBE_TYPE_BUFFER и/или GST_PAD_PROBE_TYPE_BUFFER_LIST.

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

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

Сравните вывод результирующего приложения с выводом, полученным в результате выполнения команды "gst-launch-1.0 videotestsrc ! xvimagesink" для того, чтобы понять, какие строки следует искать.

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

Зонды для работы с точками соединения лучше всего подходят для установления факта передачи данных через точку соединения. В том случае, если вам необходимо модифицировать данные, лучшим решением является разработка вашего собственного элемента фреймворка GStreamer. Такие базовые классы, как GstAudioFilter, GstVideoFilter или GstBaseTransform позволяют достаточно просто сделать это.

Если же вы хотите исключительно исследовать буферы данных по мере их прохождения через конвейер, вам даже не придется настраивать зонды для точек соединения. Вы можете просто добавить в конвейер элемент передачи данных потока без модификации (identity) и установить обработчик для его сигнала "handoff". Элемент передачи данных потока потока без модификации также предоставляет несколько полезных инструментов для отладки, таких, как свойство "dump" или свойство "last-message" (последнее активируется путем передачи параметра -v приложению gst-launch и установки значения FALSE свойства "silent" элемента передачи данных потока без модификации).

19.1.2. Проигрывание фрагмента мультимедийного файла

С помощью следующего примера мы продемонстрируем методику проигрывания фрагмента мультимедийного файла. Наша задача заключается в проигрывании только фрагмента файла начиная с 2 секунды и заканчивая 5 секундой с последующей отправкой сообщения об окончании мультимедийного потока (EOS).

На первым шаге мы переводим элемент uridecodebin в состояние "пауза" (PAUSED) и убеждаемся в том, что заблокировали все точки соединения, которые создали. Когда все выходные точки соединения элемента будут заблокированы, на все эти точки прибудут данные и мы сможем сделать вывод о том, что элемент uridecodebin подготовлен к работе.

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

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

Ниже приведен пример приложения, которое четко соответствует описанному алгоритму.

Обратите внимание на то, что мы используем специальное сообщение, заданное на уровне приложения, которое позволяет нам отправить сигнал о готовности элемента uridecodebin в главный программный поток приложения. В главном программном потоке будет осуществлено перемещение к заданному фрагменту мультимедийного потока с опустошением буферов. В процессе опустошения буферов точка соединения будет разблокирована и снова заблокирована при поступлении новых данных. Мы устанавливаем момент этой второй блокировки для удаления всех зондов. Далее мы переводим конвейер в состояние "проигрывается" (PLAYING) для проигрывания фрагмента со 2 по 5 секунду, после чего принимаем сообщение о завершении потока (EOS) и завершаем работу приложения.

19.2. Передача данных конвейеру и прием данных от него в ручном режиме

Многие разработчики изъявили желание использовать свои собственные источники данных для передачи данных конвейеру. Некоторые разработчики также изъявили желание захватывать выходные данные конвейера для обработки этих данных средствами их приложений. Хотя использовать оба этих метода настоятельно не рекомендуется, фреймворк GStreamer поддерживает такие режимы работы. Будьте осторожны! Вам следует четко понимать, что вы делаете. Так как у вас не будет возможности использования функций базового класса, вам придется до конца разобраться в принципах работы механизмов изменения состояний и синхронизации. Если ваше приложение не будет работать, следует четко понимать, что существует миллион способов стрельнуть в собственную ногу. Всегда лучше просто разработать плагин и позволить базовому классу взять на себя управление им. Обратитесь к Руководству разработчика плагинов для получения дополнительной информации по этой теме. Также обратитесь к следующему разделу, в котором будут приведены пояснения относительно статического встраивания плагинов в ваше приложение.

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

И элемент appsrc, и элемент appsink, предоставляет 2 варианта API. Первый вариант API использует стандартные для объектной модели GObject сигналы и свойства. Этот же API доступен и в форме обычного API для языка программирования C. API для языка программирования C является более производительным, но требует от вас связывания приложения с библиотекой для разработки приложений с целью использования элементов.

19.2.1. Передача данных конвейеру с помощью элемента appsrc

В первую очередь рассмотрим некоторые примеры использования элемента appsrc, который позволяет передавать данные от приложения конвейеру. Элемент appsrc поддерживает некоторые свойства, устанавливающие режим его работы. Вы должны определиться со значениями следующих свойств:
  • Будет ли элемент appsrc работать в режиме заполнения или передачи. Свойство типа потока "stream-type" может быть использовано для управления режимом работы. Тип потока со случайным доступом "random-access" позволит активировать механизм планирования для режима передачи, в то время, как использование других типов потоков приводит к активации режима заполнения.
  • Возможности буферов данных, которые передает элемент appsrc. Они должны быть установлены с помощью свойства элемента "caps". Необходимо установить фиксированные свойства, которые будут использоваться для согласования форматов при передаче потока вперед по конвейеру.
  • Работает ли элемент в режиме реального времени или нет. Эта настройка может быть осуществлена с помощью свойства "is-live". При работе в режиме реального времени важно установить минимальное и максимальное время задержки с помощью свойств "min-latency" и "max-latency" элемента appsrc. В качестве минимального времени задержки должен использоваться промежуток времени между захватом буфера и передачей его элементу appsrc. В режиме реального времени вы должны устанавливать метки времени на основе затраченного времени конвейера для буферов в момент захвата первого байта буфера перед передачей этого буфера элементу appsrc. Вы можете позволить элементу appsrc самостоятельно устанавливать метки времени для буферов с помощью свойства "do-timestamp" (но после этого минимальное время задержки должно быть равным 0, так как метки времени основываются на затрачиваемом времени конвейера в момент достижения буфером элемента appsrc).
  • Формат события SEGMENT, которое будет передаваться элементу appsrc. Формат устанавливает способ расчета затраченного времени для меток времени буферов, поэтому вы должны убедиться, что разобрались в данном вопросе. Для источников данных реального времени вы, скорее всего, должны будете установить значение свойства формата GST_FORMAT_TIME. Для источников, не относящихся к источникам реального времени, формат зависит от типа мультимедийных данных, с которыми вы работаете. Если вы планируете устанавливать метки времени для буферов, вы, скорее всего, должны будете использовать формат GST_FORMAT_TIME, в противном случае может быть использован формат GST_FORMAT_BYTES.
  • В том случае, если элемент appsrc работает в режиме случайного доступа, важно установить значение свойства "size" элемента appsrc, соответствующее количеству байт в потоке. Это позволит расположенным далее в конвейере элементам получить информацию о размере мультимедийного потока и осуществлять перемещения по направлению к концу потока по мере необходимости.

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

Свойство "max-bytes" позволяет установить, как много данных может быть помещено в очередь ожидания элемента appsrc перед тем, как он посчитает, что очередь заполнена. Заполнение внутренней очереди всегда будет приводить к отправке сигнала "enough-data", который предназначен для информирования приложения о том, что оно должно прекратить добавлять данные в очередь элемента appsrc. Свойство "block" позволяет элементу appsrc блокировать функцию передачи буфера до того момента, когда во внутренней очереди снова освободится место.

В момент, когда во внутренней очереди заканчиваются данные, генерируется сигнал "need-data", который сообщает приложению о том, что оно должно снова начать передавать данные элементу appsrc.

В дополнение к сигналам "need-data" и "enough-data" элемент appsrc может генерировать сигнал "seek-data" в том случае, если в качестве значения свойства режима потока "stream-mode" использованы идентификаторы потока с возможностью перемещения "seekable" или "random-access". Аргумент сигнала будет содержать новую желаемую позицию в потоке, описанную с использованием единиц, установленных с помощью свойства формата единиц "format". После приема сигнала "seek-data" приложение должно начать передачу буферов с новой позиции.

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

Эти сигналы позволяют приложению управлять элементом appsrc в режимах заполнения и передачи таким образом, как будет описано далее.

19.2.2. Использование элемента appsrc в режиме заполнения

В том случае, если элемент appsrc настроен для работы в режиме заполнения (значением описывающего режим потока свойства "stream-type" является "stream" или "seekable"), приложение будет периодически вызывать метод передачи буфера, который должен использовать новый буфер. Дополнительно заполнение очереди данных элемента appsrc может контролироваться с помощью сигналов "enough-data" и "nedd-data", при обработке которых необходимо приостанавливать и начинать отправку буферов с помощью соответствующей функции. Значение свойства "min-percent" описывает, насколько должна быть пуста внутренняя очередь элемента appsrc для того, чтобы был сгенерирован сигнал "need-data". Вы можете использовать некоторое значение > 0 для того, чтобы избежать опустошения описанной внутренней очереди.

Если же значением свойства "stream-type" является "seekable", не следует забывать о реализации функции обратного вызова для перемещения в массиве данных.

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

19.2.3. Использование элемента appsrc в режиме передачи

В режиме передачи данные отправляются элементу appsrc из обработчика сигнала "need-data". Вам следует передавать именно то количество байт, которое запрашивается с помощью сигнала "need-data". Вы можете передать меньшее количество байт только в том случае, если происходит обработка окончания потока.

Используйте данную модель при наличии доступа к файлу или другим хранилищам данных с произвольным доступом.

19.2.4. Пример работы с элементом appsrc

Данный пример приложения будет генерировать черные/белые поля (переключение между цветами происходит каждую секунду) в формате видеоданных и выводить их с помощью окна с оверлеем Xv, причем элемент appsrc будет использоваться в качестве источника данных с установленными возможностями для принудительного выбора формата. Мы используем элемент преобразования цветового пространства для того, чтобы быть уверенными в том, что вашему серверу оконной системы X передаются данные в корректном формате. В коде примера мы объявляем переменную частоту кадров видеопотока (0/1), а также устанавливаем метки времени для выходных буферов таким образом, что в течение секунды будут выводиться 2 кадра.

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

19.2.5. Захват данных с помощью элемента appsink

В отличие от элемента appsrc, методика работы с элементом appsink является немного более простой. Этот элемент также поддерживает базовые модели заполнения и передачи для получения данных конвейера.

Обычный способ получения сэмплов от элемента appsink связан с использованием методов gst_app_sink_pull_sample () и gst_app_sink_pull_preroll () или с использованием сигналов "pull-sample" и "pull-preroll". Упомянутые методы блокируются до того момента, когда сэмпл становится доступным для элемента, элемент деактивируется или достигается конец мультимедийного потока (EOS).

Внутренние механизмы элемента appsink используют очередь для накопления буферов, полученных из программного потока, предназначенного для обработки мультимедийного потока. В том случае, если приложение не передает сэмплы достаточно быстро, через некоторое время для хранения этой очереди будет использован большой объем памяти. Свойство "max-buffers" может использоваться для ограничения размера очереди. Свойство "drop" определяет, будет ли блокироваться программный поток для обработки мультимедийного потока при достижении максимального размера очереди или в этом случае будут просто уничтожаться устаревшие буферы. Учтите, что блокировка программного потока, предназначенного для обработки мультимедийного потока, может негативно повлиять на производительность мультимедийного приложения, работающего в реальном времени, поэтому ее следует избегать.

В том случае, если блокирование нежелательно, установка значения TRUE свойства "emit-signals" позволит элементу appsink генерировать сигналы "new-sample" и "new-preroll" в моменты, когда сэмпл может быть передан без блокировки.

Свойство "caps" элемента appsink может использоваться для управления форматами потока, которые может принимать элемент appsink. Это свойство может содержать не фиксированные возможности, причем в этом случае информация о формате переданных сэмплов может извлекаться путем получения возможностей самих сэмплов.

В том случае, если один из методов получения сэмплов от элемента appsink возвращает значение NULL, можно сделать вывод о том, что элемент appsink прекратил свою работу или получил сообщение об окончании потока (EOS). Вы можете убедиться в том, что достигнут конец потока, проверив значение свойства "eos" или использовав метод gst_app_sink_is_eos ().

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

Также следует рассмотреть возможность использования следующих свойств элемента appsink:
  • Свойства "sync" в том случае, если вы хотите, чтобы базовый класс элемента вывода данных синхронизировал буфер с таймером конвейера перед передачей вам сэмпла.
  • Свойства "qos" для активации механизма определения "качества обслуживания" (Quality-of-Service). В том случае, если вы работаете с раскодированными видеокадрами и позволяете базовому классу элемента вывода данных выполнять синхронизацию с таймером конвейера, разрешение на передачу событий QOS против направления конвейера может оказаться хорошей идеей.
  • Свойства "caps", содержащего описания принятых возможностей. Элементы, расположенные до элемента appsink в конвейере, будут пытаться осуществить преобразование формата данных таким образом, чтобы он соответствовал возможностям элемента appsink. При этом вы все также должны использовать объекты сэмплов типа GstSample для получения актуальных описаний возможностей буфера.

19.2.6. Пример использования элемента appsink

Ниже приведен пример кода приложения для захвата кадра из потока видеоданных с помощью элемента appsink.


Следующий раздел : 19.3. Принудительное использование заданного формата мультимедийных данных.