Быстрая разработка плугина для gstreamer
snegovick — Ср, 29/09/2010 - 15:44
Gstreamer — классная библиотека, позволяющая формировать цепочки обработки потоковых данных. Gstreamer построен на базе gobject, что дает ему introspection (удобный механизм работы со свойствами объектов в runtime) и сигналы.
Начало
По поводу написания плугинов для gstreamer есть очень хороший мануал http://www.gstreamer.net/data/doc/gstreamer/head/pwg/html/index.html.
Приведу здесь краткое руководство.
Во-первых необходимо заполучить исходники шаблона:
git clone git://anongit.freedesktop.org/gstreamer/gst-template.git
В директории gst-template/gst-plugin/tools находится утилита make_element, которая создает шаблон для плугина, достаточно указать ей название:
gst-plugin/src$../tools/make_element FilterName
На выходе будут файлы gstfiltername.c и gstfiltername.h
Я назвал свой плугин gstocv.
К сожалению Makefile.am утилитка не правит, поэтому придется сделать это вручную, заменив имя плугина с дефолтного на желаемое.
После этого можно попробовать собрать плугин:
gst-plugin$ bash ./autogen.sh gst-plugin$ make && make install
Можно, однако, между вызовом autogen.sh и make выполнить промежуточный шаг, указав путь, который будет использован при установке плугина (configure --prefix=…). Если этого не сделать, то по умолчанию используется /usr/local. Путь с префиксом отличным от /usr придется добавлять в переменную окружения GST_PLUGIN_PATH.
После установки с плугином можно немного поиграться. Например использовать возможности introspection:
$ gst-inspect ocv
В ответ получим развернутую характеристику шаблонного плугина:
Factory Details: Long name: ocv Class: FIXME:Generic Description: FIXME:Generic Template Element Author(s): snegovick <<user@hostname.org>> Rank: none (0) Plugin Details: Name: ocv Description: Template ocv Filename: /usr/local/lib/gstreamer-0.10/libgstocv.so Version: 0.10.0 License: LGPL Source module: my-plugin-package Binary package: GStreamer Origin URL: http://gstreamer.net/ GObject +----GstObject +----GstElement +----Gstocv Pad Templates: SINK template: 'sink' Availability: Always Capabilities: ANY SRC template: 'src' Availability: Always Capabilities: ANY Element Flags: no flags set Element Implementation: Has change_state() function: gst_element_change_state_func Has custom save_thyself() function: gst_element_save_thyself Has custom restore_thyself() function: gst_element_restore_thyself Element has no clocking capabilities. Element has no indexing capabilities. Element has no URI handling capabilities. Pads: SRC: 'src' Implementation: Pad Template: 'src' SINK: 'sink' Implementation: Has chainfunc(): gst_ocv_chain Pad Template: 'sink' Element Properties: name : The name of the object flags: readable, writable String. Default: null Current: "ocv0" silent : Produce verbose output ? flags: readable, writable Boolean. Default: false Current: false
В частности sink и src capabilities показывают, что сейчас наш плугин принимает все что угодно и отдает все что угодно. Наш плугин будет делать преобразование canny над серой картинкой с глубиной цвета 1 байт. Поэтому в gstocv.c необходимо заменить
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("ANY") ); static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS ("ANY") );
на
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/x-raw-gray, bpp=8") ); static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/x-raw-gray, bpp=8") );
Теперь можно пересобрать плугин и попробовать погонять через него видео поток.
Специально для тестов я написал небольшой скриптик, который конструирует конвеер (pipeline) гстримера таким образом, чтобы можно было смотреть видеопоток до нового плугина и после него в разных окнах.
gst-launch v4l2src device=/dev/video0 ! 'video/x-raw-yuv,width=640,height=480,framerate=30/1' ! tee name=t_vid \ ! queue ! xvimagesink sync=false t_vid. \ ! queue ! ffmpegcolorspace ! ocv ! ffmpegcolorspace ! sdlvideosink
Замечу, что ocv обрамлен в конвеере элементами ffmpegcolorspace ввиду того, что необходимо преобразовать исходный поток, который в моем случае состоит из YUV кадров в поток grayscale кадров. Назначение второго ffmpegcolorspace заключается в преобразовании серых кадров в формат, принимаемый элементом sdlvideosink. Почти всегда конвеер может выбрать правильные цветовые форматы сам, основываясь на требованиях sink и src pad`ов элементов. При подборе элементов полезно пользоваться опцией -vvv утилиты gst-launch, которая позволяет отслеживать проблемы и цветовые форматы различных элементов.
В результате получается следующая картинка:

OpenCV
Следующим шагом я хочу добавить какой-нибудь фильтр OpenCV. Можно было бы найти алгоритмы и написать реализации самому, но так как времени у меня до соревнований уже в обрез, я решил не издеваться над собой и не проводить за компьютером бессонные ночи, а взять готовые, достаточно быстрые реализации алгоритмов.
Сначала я решил попробовать добавить преобразование Canny, цель которого — выделение границ областей.
Неприятный момент, связанный с OpenCV заключается в том, что эта библиотека написана на C++, но тут ничего не сделаешь.
Итак, для начала необходимо научить autotools собирать плугин с помощью компилятора g++:
в файле configure.ac необходимо заменить
AC_PROG_CC
на
AC_PROG_CXX
Cменить расширения исходных исходных файлов плугина на что-то соответствующее компилятору, скажем cxx.
Заменить
libgstocv_la_CFLAGS = $(GST_CFLAGS)
на
libgstocv_la_CXXFLAGS = $(GST_CFLAGS)
также поправить расширения исходных файлов в src/Makefile.am.
После этого необходимо снова запустить autogen.sh и настроить пути установки плугина, а после этого собрать его и установить с помощью make clean; make && make install. На данном этапе необходимо добиться успешной сборки, чтобы двигаться дальше.
Теперь добавляем библиотеку OpenCV:
в configure.ac:
dnl required version of opencv OPENCV_REQUIRED=2.1.0 PKG_CHECK_MODULES(OPENCV, [ opencv >= $OPENCV_REQUIRED ], [ AC_SUBST(OPENCV_CFLAGS) AC_SUBST(OPENCV_LIBS) ], [ AC_MSG_ERROR([ You need to install or upgrade the OpenCV development packages on your system. The minimum version required is $OPENCV_REQUIRED. ]) ])
В Makefile.am к CXXFLAGS и LDFLAGS дописать соответственно $(OPENCV_CFLAGS) и $(OPENCV_LIBS).
Для осуществления преобразований нам нужно будет знать ширину и высоту картинки. Выяснить эти параметры можно на этапе установки caps`ов потока.
В gstocv.hxx, в struct _Gstocv
int width;int height;
в функцию _set_caps:
GstStructure *structure = gst_caps_get_structure (caps, 0); gst_structure_get_int (structure, "width", &filter->width); gst_structure_get_int (structure, "height", &filter->height);
Значения, полученные в функции _set_caps будут сохранться в переменных width и height элемента.
в _chain:
int sz = 0; if ((sz = GST_BUFFER_SIZE(buf)) != 0) { IplImage * src = cvCreateImageHeader(cvSize(filter->width, filter->height), 8, 1); src->imageData = (char*)GST_BUFFER_DATA(buf); src->imageDataOrigin = (char*)GST_BUFFER_DATA(buf); GstBuffer *buffer = gst_buffer_new_and_alloc(sz); IplImage * dst = cvCreateImageHeader(cvSize(filter->width, filter->height), 8, 1); dst->imageData = (char*)GST_BUFFER_DATA(buffer); dst->imageDataOrigin = (char*)GST_BUFFER_DATA(buffer); cvCanny( src, dst, 50, 200, 3 ); gst_buffer_copy_metadata (buffer, buf, (GstBufferCopyFlags)GST_BUFFER_COPY_ALL); gst_buffer_unref (buf); return gst_pad_push (filter->srcpad, buffer); } else GST_WARNING ("zero sized buffer");
Здесь необходимо обеспечить сопряжение интерфейсов gstreamer и opencv. Для этого воспользуемся функцией cvCreateImageHeader, описанной в документации OpenCV.
В результате получается следующая картинка:
В следующий раз я хочу добавить элемент, который будет сегментировать картинку и искать на ней контрастную полосу и исходя из параметров полосы — выдавать управление робота.

snegovick, спасибо за столь
Timpson (не проверено) — Чт, 21/04/2011 - 12:52snegovick, спасибо за столь интересную статью.
Я сам недавно сел за разработку плугинов для GStreamer (до этого занимался DirectShow-фильтрами).
И вот, назрел вопрос после некоторых затруднений, связаных с C++.
Мой код был разработан под Windows DirectShow с испоьзованием объектов. Но сам gst-template генерирует .c - файл плагина.
В Линуксе сижу совсем недавно, и хотелось бы спросить ссылочки для настройки Makefile'ов. Потому как мне не помогли методы описанные в статье, make выдаёт:
*** Нет правила для сборки цели `temporal_walsh_hadamard.cpp', требуемой для `libgstplugin_la-temporal_walsh_hadamard.lo'. Останов.
Тоже происходит и с другими модулями.
При замене в makefile'е .c на .сpp ругается на то что нет .c файла.
Возможно я не сильно глубоко постиг ДАО-make!
Дело в том, что настройка
snegovick — Втр, 03/05/2011 - 22:33Дело в том, что настройка Makefile.am и Makefile.in к собственно Makefile имеет весьма опосредованное отношение, по automake/autoconf которые используются в этом шаблоне могу рекомендовать http://sourceware.org/autobook/autobook/autobook_toc.html#SEC_Contents .
Если это не особо поможет, то предлагаю вам разместить ваши Makefile.in, Makefile.am на чем-нибудь типа pastebin.com и кинуть сюда ссылки, будем разбираться что неработает.
Вообще я конечно в восторге от концепции конвеера gstreamer и легкости его расширения, надеюсь у вас все получится со временем.
Да, спасибо!С .cpp вроде бы
Timpson (не проверено) — Втр, 17/05/2011 - 18:12Да, спасибо!
С .cpp вроде бы разобарлся. Нужно было удалять файлы Makefile и Makefile.in и затем перезапускать autogen.sh.
Вот мой скрипт для сборки плагина (использую Ubuntu):
cd ~/plugin/myplugin2
sudo make clean
cd ~/plugin/myplugin2/src
sudo rm -f Makefile
sudo rm -f Makefile.in
cd ~/plugin/myplugin2
sudo sh autogen.sh
sudo make
sudo cp src/.libs/myplugin2.so /usr/lib/gstreamer-0.10/myplugin2.so
gst-inspect myplugin2.so
В таком варианте плагин собирается, но сейчас встала проблема, что gst-inspect выдаёт undefined symbol: _Z7getbitsh
Вроде бы и порядок в мейкфайле выстроил как надо, и .h-файлы в нужном порядке, а ругается.
snegovick, нет ли рускоязычных ресурсов по GSreamer? Я сам некотрое время разрабатывал фильтры (плагины) для DirectShow, и есть форум на directshow.wonderu.com, на котором есть описание DirectShow и примеры, и подскажут - если что. А вот по GStreamer'у не могу найти.
А так конечно, гораздо удобнее с GStreamer'ом работать. Да что уж говорить, он и быстрее!
По поводу русскоязычных
snegovick — Ср, 18/05/2011 - 23:41По поводу русскоязычных ресурсов к сожалению не могу ничего толком подсказать.
Те команды которые вы привели в своем комментарии несколько избыточны: во-первых нет необходимости использовать sudo в каждой команде - все что вы написали кроме cp должно выполняться с правами пользователя (однако после того как вы первый раз запустили autogen.sh и make под sudo - сгенерированные файлы будут принадлежать пользователю root, поэтому чтобы запускать make и autogen.sh впредь от имени пользователя, придется удалить все сгенерированные файлы. В этом вам поможет make clean; make distclean, однако они удалят не весь мусор autotools, что-то придется удалить руками).
Далее по поводу необходимости удаления *.in файлов - ее нет. После того как вы поменяли файлы configure.ac или Makefile.am - достаточно запустить autogen.sh или, если вы его уже ранее запускали - выполнить autoreconf. Тогда automake/autoconf сгенерируют новые Makefile.in и Makefile с учетом ваших изменений. Копировать файлы вручную в /usr не нужно. Достаточно выполнить make install (директория в которую make установит файлы указывается на этапе configure опцией --prefix, так чтобы установить в /usr - нужно указать ./configure --prefix=/usr . configure выполняется сразу после autogen.sh или autoreconf, перед make).
Ну а проблема с которой вы столкнулись используя gst-inspect скорее всего связана с тем что вы забыли подключить библиотеку в которой содержится указанный символ (или перепутали имя функции и т.д.) на этапе линковки плугина (добавлять библиотеки можно например в файле Makefile.am в директории вашего плугина, не забудьте перекомпилировать и установить плугин).
Кроме того, я заметил что вы пишете .so в конце имени плугина - в этом нет необходимости. Выведите весь список плугинов которые известны gstreamer и найдите среди них свой - там будет указано имя под которым его знает gstreamer:
gst-inspect | grep myplugin2
При выполнении гайда возникла
Wizzy (не проверено) — Сб, 13/04/2013 - 15:05Давайте разбираться по шагам
snegovick — Сб, 13/04/2013 - 17:531. Скопировал себе
Wizzy (не проверено) — Втр, 16/04/2013 - 12:38Попробуйте перед выполнением
snegovick — Ср, 17/04/2013 - 21:03Добрый день. А есть
Гость (не проверено) — Пнд, 20/02/2017 - 20:47Добрый день. А есть исходники, описанные в статье на гитхабе или иных ресурсах? Очень интересно прочитать продолжение.
Отправить комментарий