Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Пишем плагин для GStreamer на MS Visual Studio

Anna | 24.06.2014 | нет комментариев

Меня неизменно волновали прикладные задачи обработки видеоданных в настоящем времени. На Прогре я прочитал серию статей о мультимедиа фреймвоке GStreamer:

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

И вот некогда, в процессе работы над планом, мне потребовалось организовать на объекте систему видеонаблюдения и интегрировать ее в систему учета. Эта задача была удачно решена экспертам нашей компанией и не достойна внимания широкой общественности. Система учета работает на Microsoft .NET, все камеры выдают H264 RTSP поток. Для захвата видео применяется торговая библиотека MediaSuite от Streamcoders.

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

Выходит, дано:

  • RTSP H264 источник
  • Система Windows 7 32-bit
  • MS Visual Studio 2010
  • Язык С
  • GStreamer 1.0

Нужно получить:

  • поток видео, содержащий итоги обработки

Метод решения:

  • Разработка плагина для GStreamer 1.0

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

Установка GStreamer

Загружаем и устанавливаем GStreamer gstreamer-1.0-ххх-1.2.4.msi. Его дозволено взять тут.
Для разработки, нам также потребуется дистрибутив gstreamer-1.0-devel-xxx.msi скажем, gstreamer-1.0-devel-x86-1.2.4.msi, В процессе установки выбираем нужные опции:

Забегая вперед, скажу, отличнее будет установить Windows Device Driver Kit 7.1.0. По-умолчанию он ставится в C:WinDDK7600.16385.1 и именно там его будет искать Visual Studio при построении плана. Если у вас теснее установлен DDK по иному пути, это дозволено будет исправить потом, непринужденно в настройках плана.

На сайте плана GStreamer среди прочей документации есть начальство для разработчиков плагинов. Дозволено прочитав начальство написать каждый код самому, но есть вероятность скачать образец плана плагина, из репозитория.

Образец содержит начальные файлы с и скрипт для генерации кода плагина. Как гласит инструкция, позже развертывания образца из репозитория, нужно перейти в директорий gst-template/gst-plugin/src и запустить утилиту ../tools/make_element. Утилита make_element имеет два параметра: имя плагина (dummy), имя начального файла, тот, что будет использован (gstplugin по-умолчанию).

В итоге выполнения мы получим два файла: gstdummy.c и gstdummy.h. Внутри будет скелет плагина dummy, тот, что еще тупой и нечего не делает, но теснее может быть встроен в систему плагинов фреймвока.

Маленькая ремарка: все, что сказано выше, объективно для Linux, Unix машин, а как быть скорбным владельцам Windows? Cmd.exe не станет исполнять make_element. Если заглянуть вовнутрь make_element станет ясно, что ничего трудного он не делает, а с поддержкой потокового редактора sed изготавливает генерацию целевых исходников на основании данных ему параметров. Это дозволено сделать и самому. На каждый случай, я сотворил репозиторий, куда по ходу становления буду помещать свой тестовый план:github.com/nostrum-service/gst.

Позже того, как мы проделали заблаговременную работу, настал черед образования плана непринужденно в MS Visual Studio 2010. К счастью, разработчики GStreamer позаботились о пользователях Visual Studio и разместили в дистрибутив все нужное для создания плана. Нужно только верно поместить файлы в каталогах Visual Studio.
Все нужное лежит в директории gstreamer1.0x86sharevs2010.
Исполняем:

xcopy c:gstreamer1.0x86sharevs2010gst-template*.* "C:Program FilesMicrosoft Visual Studio 10.0VCVCWizardsgst-template*.*" /s /e /c
xcopy C:gstreamer1.0x86sharevs2010wizard*.* "C:Program FilesMicrosoft Visual Studio 10.0VCvcprojects"

Запускаем Visual Studio (либо перезапускаем, Дабы она увидела новые настройки), создаем новейший план, и выбираем из установленных образцов Visual C gst-dk-template.

Если все прошло типично, создастся пустой план с нужными настройками. От того что, мы хотим сделать плагин, идем в настройки плана и меняем в Project Details Configuration Type с Application (.exe) на Dynamic Library (.dll).

В окне Property Manager отслеживаем следующую картину (включить Property Manager дозволено View->Other Windows->Property Manager):

В сделанный пустой план нужно включить файлы, которые были сделаны ранее с поддержкой утилиты make_element.

Компилируем, если все верно, получаем готовый DLL, тот, что нужно скопировать в каталог плагинов GStreamer (у меня — C:gstreamer1.0x86libgstreamer-1.0).
На каждый случай проверим: gst-inspect-1.0 dummy. Тут мы увидим, что узнал GStreamer о нашем плагине.

Наименьший комплект функций плагина

Для того Дабы встроить плагин в цепочку, нам нужно реализовать дальнейший жизненный цикл:

  • осведомить фреймвоку данные о себе (инициализировать класс)
  • произвести инициализацию экземпляра плагина
  • обработать процесс подключения потока
  • сделать что-то с входными данными и передать их на выход
  • по заключению очистить занятые источники
Метаданные

За предоставление метаданных о плагине у нас отвечает функция
static void gst_dummy_class_init (GstdummyClass * klass)

В нашем примере элемент dummy имеет качество Silent типа Boolean, отвечающее за итог текста при обработке потока.

  gobject_class->set_property = gst_dummy_set_property;
  gobject_class->get_property = gst_dummy_get_property;

  g_object_class_install_property (gobject_class, PROP_SILENT,
      g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
          FALSE, (GParamFlags)G_PARAM_READWRITE));

Этим кодом мы информируем среде GStreamer о том, что у плагина есть качество Silent, оно имеет тип Boolean, за его установку отвечает делегат gst_dummy_set_property, чтение — gst_dummy_get_property, оно доступно по чтению и записи, значение по-умолчанию – FALSE. Дальше мы регистрируем точки подключения к плагину – pads.

  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&src_factory));
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&sink_factory));

Определяем входной pad sink, тот, что имеется неизменно в присутствие — 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 ("ANY")
    );

Определяем выходной pad src, тот, что имеется неизменно в присутствие — 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")
    );
Инициализация экземпляра

В процессе построения pipeline, среда GStreamer вызывает функцию инициализации экземпляра плагина:

static void
gst_dummy_init (Gstdummy * filter)

на вход которой подается конструкция, которую нужно заполнить:

struct _Gstdummy
{
  GstElement element;
  GstPad *sinkpad, *srcpad;
  gboolean silent;
};

Для того, Дабы обрабатывать события, протекающие на входе плагина, нужно указать соответствующий делегат:

gst_pad_set_event_function (filter->sinkpad, GST_DEBUG_FUNCPTR(gst_dummy_sink_event));
Подключение к потоку

При появлении событий на входе плагина, в нашем случае будет вызвана функция:

static gboolean
gst_dummy_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)

которая пока ничего не делает.

Пробный запуск

Сейчас дозволено испробовать запустить — gst-launch-1.0 videotestsrc! dummy! autovideosink –v. Данная команда передает тестовый поток видео сгенерированный videotestsrc на наш плагин, тот, что передает его дальше без изменений на видео проигрыватель autovideosink. Ключ v разрешает увидеть, как происходит обработка каждой цепочки.

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

/GstPipeline:pipeline0/GstVideoTestSrc:videotestsrc0.GstPad:src: caps = video/x-raw, format=(string)I420, width=(int)320, height=(int)240, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive

Из этого следует, что экземпляр класса GstVideoTestSrc с именем videotestsrc0 предоставил pad src, выдающий поток video/x-raw в формате I420 размерами кадра 320 на 240 и т.д.
От того что наш плагин может принять всякий формат, его вход связался с выходом videotestsrc0:

/GstPipeline:pipeline0/Gstdummy:dummy0.GstPad:sink: caps = video/x-raw, format=(string)I420, width=(int)320, height=(int)240, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive
Последующее погружение

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

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

struct _elements_entry
{
  const gchar *name;
    GType (*type) (void);
};

static const struct _elements_entry _elements[] = {
  {"dummy", gst_dummy_get_type},
  {"painter", gst_painter_get_type},
  {NULL, 0},
};

static gboolean
plugin_init (GstPlugin * plugin)
{
  gint i = 0;

  while (_elements[i].name) {
    if (!gst_element_register (plugin, _elements[i].name,
            GST_RANK_NONE, (_elements[i].type) ()))
      return FALSE;
    i  ;
  }

  return TRUE;
}

Для painter я сотворил больше суровые ограничения на входной формат потока. Сейчас это выглядит дальнейшим образом:

static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
	GST_PAD_SINK,
	GST_PAD_ALWAYS,
	GST_STATIC_CAPS ( GST_VIDEO_CAPS_MAKE ("{ BGRx }") )
	);

Это значит, что на вход может подаваться потоковое видео в формате BGRx с любым разрешением и частотой кадров. OpenCV по-умолчанию использует схему BGR. Про цветовые схемы и реформирования дозволено почитать тут.
От того что, волнующая меня камера выдает RTSP H264 поток, нам нужно его раскодировать и подать на вход преобразова

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB