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 розділів, присвячених детальному аналізу проєкту.