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

UnixForum





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

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

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

Глава 17. Программные потоки

Фреймворк GStreamer является многопоточным и полностью потокобезопасным. Большая часть механизмов управления программными потоками скрыта от приложения с целью упрощения процесса его разработки. Однако, в некоторых случаях при разработке приложения может возникнуть необходимость в воздействии на ряд аспектов работы механизма управления программными потоками. Фреймворк GStreamer позволяет приложениям принудительно использовать множество программных потоков в некоторых частях конвейера. Обратитесь к разделу ниже под названием "Когда вы можете предпочесть принудительное использование программного потока?" для ознакомления с подробностями.

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

17.1. Планирование работы элементов в рамках фреймворка GStreamer

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

В любом случае некоторые элементы будут создавать программные потоки, называемые "программными потоками, предназначенными для обработки мультимедийных потоков" ("streaming threads") для своих целей, заключающихся в обработке мультимедийных данных. Программные потоки, предназначенные для обработки мультимедийных потоков или объекты задач типа GstTask создаются в рамках объекта пула задач типа GstTaskPool в момент, когда элементу необходим программный поток для обработки мультимедийного потока. В следующем разделе мы познакомимся с методом получения уведомлений о состоянии упомянутых объектов задач и объектов пулов задач.

17.2. Конфигурация программных потоков в рамках фреймворка GStreamer

Сообщение STREAM_STATUS передается с помощью шины сообщений для информирования вас о состоянии программных потоков, предназначенных для обработки мультимедийных потоков. Из упомянутого сообщения вы можете извлечь следующую информацию:
  • Перед созданием нового программного потока вы будете уведомлены с помощью сообщения типа GST_STREAM_STATUS_TYPE_CREATE. После его приема у вас появится возможность установки параметров объекта пула задач и объекта задачи типов GstTaskPool и GstTask соответственно. Специальный пул задач будет предоставлять специальные программные потоки, выполняющие функции обработки мультимедийных потоков.
    Данное сообщение должно быть обработано синхронно в том случае, если вы хотите создать специальный пул задач. В том случае, если вы не настраиваете пул задач для создания программного потока, после выхода из обработчика данного сообщения объект задачи будет использовать стандартный пул.
  • Сообщение будет отправлено при входе в программный поток и выходе из него. Это именно тот момент, когда вам следует устанавливать приоритеты программных потоков. Вы также получите уведомление в момент уничтожения программного потока.
  • Вы получите сообщения в момент, когда программный поток начнет, приостановит или завершит свою работу. Эти сообщения могут использоваться для визуализации состояния программных потоков, предназначенных для обработки мультимедийных потоков, средствами приложения с графическим интерфейсом.

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

17.2.1. Повышение приоритета программного потока

        .----------.    .----------.
        | faksesrc |    | fakesink |
        |        вых.->вход.       |
        '----------'    '----------'
Давайте рассмотрим изображенный выше простой конвейер. Нам хотелось бы повысить приоритет программного потока, предназначенного для обработки мультимедийного потока. В данном случае элемент fakesrc создает программный поток для обработки мультимедийных данных с целью генерации потока произвольных данных и передачи его связанному элементу для приема произвольных данных. Алгоритм изменения приоритета будет выглядеть аналогичным образом:
  • При переводе элемента fakesrc из состояния "готовности" (READY) в состояние "пауза" (PAUSED), ему потребуется программный поток для передачи данных элементу fakesink. Он отправит сообщение STREAM_STATUS, указывающее на его потребность в программном потоке для обработки мультимедийных данных.
  • Приложение будет обрабатывать сообщения STREAM_STATUS с помощью синхронного обработчика сообщений шины. После этого оно настроит объект специального пула задач типа GstTaskPool для размещения объекта задачи типа GstTask, передаваемой вместе с сообщением. Этот специальный пул задач отвечает за создание программных потоков. В данном примере мы будем создавать программный поток с повышенным приоритетом.
  • Альтернативным методом изменения приоритета или политики планирования исполнения текущего программного потока является обработка уведомлений о входе в программный поток и выходе из него (ENTER/LEAVE), так как синхронная обработка сообщения происходит в контексте программного потока.

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

При реализации класса пула программных потоков особенно важной является функция с именем "push", предназначенная для добавления программного потока в пул. Реализация класса должна создавать программный поток, который вызовет заданную функцию. Более сложные реализации класса могут поддерживать работу нескольких программных потоков в рамках одного пула, так как операции создания и уничтожения программных потоков не всегда являются самыми быстрыми.

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

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

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

17.3. Когда вы можете предпочесть принудительное использование программного потока?

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

Ниже приведены некоторые причины, по которым вы можете принудительно создавать программные потоки. Однако, по причинам, связанным с производительностью, вам наверняка не захочется создавать по потоку для каждого существующего элемента, так как это приведет чрезмерным затратам ресурсов. Давайте рассмотрим несколько ситуаций, в которых использование программных потоков может быть особенно полезным:
  • Буферизация данных, например, при работе с сетевыми мультимедийными потоками или при записи данных из такого источника мультимедийного потока реального времени, как видеокарта или аудиокарта. В этом случае кратковременные задержки в каких-либо частях конвейера не приведут к потере данных. Также имеет смысл обратиться к разделу с названием "Буферизация потока" для ознакомления с механизмом буферизации потока на основе элемента queue2.
    Рисунок 17.1. Буферизация потока данных из сетевого источника
    Буферизация потока данных из сетевого источника
  • Синхронизация устройств для вывода данных, например, в процессе проигрывания потока, содержащего как видео-, так и аудиоданные. При использовании программных потоков для обоих устройств, предназначенных для вывода данных, последние будут работать независимо друг от друга и их синхронизация будет осуществляться лучшим образом.
    Рисунок 17.2. Синхронизация устройств для вывода аудио- и видеоданных
    Синхронизация устройств для вывода аудио- и видеоданных

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

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


Следующий раздел : Автоматическая подгрузка плагинов