Перейти до основного вмісту

GStreamer внизу.

У фреймворку Neat конвеєри виконуються за допомогою GStreamer. Майже все, що видно застосунку — Graph, Run, Node — є типізованою обгорткою над концепціями GStreamer. На цій сторінці пояснюється структура: що приховується, що ні, і коли використання «сирого» GStreamer є правильним рішенням.

Що саме абстрагує ця структура.

Концепція GStreamerАбстракція фреймворку
gst-launch фрагмент тексту.Node::backend_fragment(int node_index)
Назва елемента (name=…)Детермінований n<idx>_<role> з Node::element_names().
Рядок конвеєра (з’єднані фрагменти).Graph::add() створює та об’єднує.
Переговори щодо встановлення лімітівGraph::build() перевіряє обмеження за допомогою NodeCapsBehavior.
gst_pipeline_set_state()Graph::run() / Run::start()
Повідомлення в автобусі.GraphReport::bus_messages
appsrc API для надсилання данихRun::push() (лише для вузлів із InputRole::Push)
appsink: API для отримання даних.Run::pull()
Час обробки для кожного елемента.MeasureReport від Run::start_measurement().

Програма ніколи не записує рядок запуску безпосередньо, ніколи не називає елементи безпосередньо і ніколи не звертається до GStreamer C API. Усе відбувається через вузли.

Що проступає крізь матеріал?

Кілька концепцій GStreamer, які фреймворк не приховує (і не повинен приховувати):

  • Семантика заголовків — які поля містить заголовок відео- або аудіофайлу. Код програми може зчитувати FormatTag та перевіряти метадані Sample, які відображають відповідні поля заголовка.
  • Прапори буфера — розрив, кінець потоку, пропуск. Структура поширює їх на... Sample щоб код застосунку міг реагувати на межі потоку.
  • Послідовність обробки подій — GStreamer гарантує, що події (заголовки, сегменти, кінець потоку) обробляються в правильній послідовності разом із буферами. Ця структура зберігається на стороні отримання даних.

Якщо вам потрібно дізнатися точну команду запуску GStreamer для створеного графа, викличте Graph::describe() — вона генерує детермінований gst-launch скрипт, який відтворює конвеєр, копіюючи кожен байт.

Коли варто використовувати GStreamer у його базовій формі?

У звичайному коді застосунків це не потрібно. Ось випадки, коли це доцільно:

  • Спеціалізовані плагіни GStreamer — якщо вам потрібен елемент GStreamer, який не входить до стандартної поставки фреймворку як Node, створіть підклас Node, який обгорне ваш плагін і генеруватиме відповідний backend_fragment(). Див. розділ «Створення спеціалізованого Node» у детальному описі проєкту (§0.10).
  • Інструменти для діагностикиrepro_gst_launch, створений за допомогою Graph::describe(), є саме тією командою запуску, яку використовує GStreamer; ви можете скопіювати її та вставити в gst-launch-1.0 для налагодження в автономному режимі.
  • Розробка плагінів — власні плагіни SiMa для GStreamer (сімейство sima*) документовані в описі плагіна ABI (див. gst/SimaPluginStaticManifestAbi.h) і автоматично завантажуються фреймворком.

Детермінізм гарантує.

Іменування елементів у фреймворку є детермінованим — один і той самий список вузлів з однаковими параметрами завжди генерує один і той самий рядок gst-launch. Саме це забезпечує:

  • Поле repro_gst_launch фактично відтворюється.
  • Знімки еталонних результатів тестування залишаються стабільними під час повторних запусків.
  • Ідентифікація елементів (наприклад, для визначення джерела вимірювань) у форматі, зручному для машинної обробки.

За домовленістю використовується n<node_index>_<role>, де role — це короткий, стабільний ідентифікатор, який обирає автор Node. Детальніше про загальнодоступні обгортки Node, що беруть участь у цій схемі іменування, див. у Група API для вузлів.

Для подальшого ознайомлення

  • «Абстракція GStreamer» — розділ 0.8 у детальному аналізі проєкту.
  • Інтерфейси прикладних програм для вузлів — це конкретні обгортки для Node, які генерують детерміновані фрагменти бекенду.
  • Graph::describe() — вивести рядок запуску.
  • «Маніфест плагіна SiMa» — §51 і §95 розділів, присвячених детальному аналізу проєкту.