提交 ff33b0f9 编写于 作者: O openvino-pushbot

Publishing 2019 R1

上级
---
# Language: Cpp
BasedOnStyle: LLVM
ColumnLimit: 120
IndentWidth: 4
AllowShortFunctionsOnASingleLine: None
AllowShortBlocksOnASingleLine: false
AlwaysBreakTemplateDeclarations: Yes
CompactNamespaces: false
...
.git/
.gitignore
build/
_release/
docker/**/*.tgz
docker/**/*.tar.gz
CMakeCache.txt
CMakeFiles
CMakeFiles.txt.user
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
build
.vscode
.idea
_release
# Compiled Object files
*.o
*.obj
# Compiled Dynamic libraries
*.so
# Compiled Static libraries
*.a
# ==============================================================================
# Copyright (C) <2018-2019> Intel Corporation
#
# SPDX-License-Identifier: MIT
# ==============================================================================
cmake_minimum_required (VERSION 3.1)
project(VA_GStreamer_Plugins)
if(NOT(UNIX))
message(FATAL_ERROR "Only UNIX supported")
endif()
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
message(STATUS "CMAKE_BUILD_TYPE is undefined. Set default build type ${CMAKE_BUILD_TYPE}.")
endif()
set(VERSION_MAJOR 0)
set(VERSION_MINOR 3)
if (NOT DEFINED VERSION_PATCH)
set(VERSION_PATCH 0)
message(WARNING "VERSION_PATCH is undefined. Set default value ${VERSION_PATCH}.")
endif()
if (NOT DEFINED GIT_INFO)
set(GIT_INFO "git_unknown")
message(WARNING "GIT_INFO is undefined. Set default value ${GIT_INFO}.")
endif()
set(PRODUCT_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(PLUGIN_VERSION ${PRODUCT_VERSION}.${GIT_INFO})
# Propagate version to plugins
add_definitions(-DPLUGIN_VERSION="${PLUGIN_VERSION}")
add_definitions(-DPACKAGE="gst-video-analytics")
add_definitions(-DPACKAGE_NAME="GStreamer Video Analytics elements")
add_definitions(-DGST_PACKAGE_ORIGIN="https://github.com/opencv/gst-video-analytics")
add_definitions(-DPLUGIN_LICENSE="MIT/X11")
macro(set_target_lib_version TARGET)
set_target_properties(
${TARGET}
PROPERTIES
SOVERSION ${VERSION_MAJOR}
VERSION ${PRODUCT_VERSION}
)
endmacro(set_target_lib_version)
if (NOT(BIN_FOLDER))
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set (ARCH intel64)
else()
set (ARCH ia32)
endif()
set (BIN_FOLDER ${ARCH})
endif()
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BIN_FOLDER}/${CMAKE_BUILD_TYPE}/lib)
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BIN_FOLDER}/${CMAKE_BUILD_TYPE}/lib)
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BIN_FOLDER}/${CMAKE_BUILD_TYPE}/bin)
set (CMAKE_DOCDIR ${CMAKE_BINARY_DIR}/${BIN_FOLDER}/${CMAKE_BUILD_TYPE}/doc)
# Common compilation flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wuninitialized -Winit-self -Wmaybe-uninitialized -Warray-bounds -fstack-protector-strong")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wuninitialized -Warray-bounds -fstack-protector-strong")
# Additional compilation flags aplied to specific targets
set(C_FLAGS -Wall -Wextra)
set(CXX_FLAGS -Wall -Wextra)
function (set_compile_flags TARGET)
target_compile_options(${TARGET} PRIVATE $<$<COMPILE_LANGUAGE:C>:${C_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>:${CXX_FLAGS}>)
endfunction(set_compile_flags)
####################################
## to use C++11
set (CMAKE_CXX_STANDARD 11)
set (CMAKE_POSITION_INDEPENDENT_CODE ON)
####################################
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
###############################################################################
option(DISABLE_VAAPI "Parameter to disable VAAPI support" ON)
option(DISABLE_SAMPLES "Parameter to disable samples building" OFF)
option(ENABLE_DOCUMENTATION "Parameter to enable documentation generation" OFF)
configure_file(cmake/config.h.in configs/config.h @ONLY)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/configs)
add_subdirectory(gst)
add_subdirectory(gst-libs)
add_subdirectory(inference_backend)
add_subdirectory(thirdparty)
if(NOT ${DISABLE_SAMPLES})
add_subdirectory(samples)
endif()
# Code style
## Source Code Formatting
We are using formatting convention based on LLVM with few changes you can find in `.clang-format` file.
## How to use .clang-format
Install clang-format-7 then configure your IDE to use it and optionally you can add symlink to make your editor automatically take it by name:
```sh
sudo apt install -y clang-format-7
sudo ln -s /usr/bin/clang-format-7 /usr/bin/clang-format
```
Instruction for CLion:
- Go to File->Settings->Tools->External Tools and click on the plus sign. A window should pop up. Choose a name, for example "clang-format"
- For the Tool settings tab use this configuration:
- Program: clang-format (you should use the name of your executable here)
- Parameters: --style=file -i $FileName$
- Working directory: $FileDir$
Now, with your file open, you can go to Tools->External tools and run the config above. It basically calls clang-format and does inplace formatting using the style define in the first .clang-format file found in a parent directory.
For VS Code use this extension [clang-format](https://marketplace.visualstudio.com/items?itemName=xaver.clang-format)
The MIT License
Copyright (c) 2018-2019 Intel Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# GStreamer Video Analytics Plugins
This is preview of the product functionality that is being introduced to gain early developer feedback. Comments, questions, and suggestions are encouraged and should be submitted to [the GitHub Issues page](https://github.com/opencv/gst-video-analytics/issues)
## Overview
This repository contains a collection of GStreamer elements to enable CNN model based video analytics capabilities (such as object detection, classification, recognition) in GStreamer framework.
The complete solution leverages
* Open source GStreamer framework for pipeline management
* GStreamer plugins for input and output such as media files and real-time streaming from camera or network
* Video decode and encode plugins, either CPU optimized plugins or GPU-accelerated plugins [based on VAAPI](https://github.com/GStreamer/gstreamer-vaapi)
and additionally installs the following Deep Learning specific elements from this repository
* Inference plugins leveraging [Intel OpenVINO](https://software.intel.com/en-us/openvino-toolkit) for high performance inference using CNN models
* Visualization of computer vision results (such as bounding boxes and labels of detected objects) on top of video stream
## License
GStreamer Video Analytics Plugins are licensed under [MIT license](LICENSE).
## Prerequisites
### Hardware
* Refer to OpenVINO SDK for [hardware requirements for inference elements](https://software.intel.com/en-us/openvino-toolkit/hardware);
* On platforms with Intel Gen graphics, refer to gstreamer-vaapi for [HW accelerated video decode and encode requirements](https://github.com/GStreamer/gstreamer-vaapi).
### Software
* Linux* system with kernel >= 4.15
* GStreamer framework >= 1.14
## Build and Run
[This link](https://github.com/opencv/gst-video-analytics/wiki/Build-and-Run) provides detailed instructions how to build plugins and run samples in [docker container](https://github.com/opencv/gst-video-analytics/wiki/Acquire-docker-image-and-run-docker-container) or [directly on host machine](https://github.com/opencv/gst-video-analytics/wiki/Build-on-host-machine).
## Samples
See [command-line examples](samples/shell) and [C++ example](samples/cpp/face_attributes)
## Reporting Bugs and Feature Requests
Bugs and requests can be reported [on Issues page](https://github.com/opencv/gst-video-analytics/issues)
## Usage and integration into application
### Pipelining and data flow
[More details](https://github.com/opencv/gst-video-analytics/wiki/Data-flow) about pipeline construction and data flow between pipeline elements
### Metadata
[More details](https://github.com/opencv/gst-video-analytics/wiki/Metadata) about metadata generated by inference plugins and attached to video frames
### Model preparation
[More details](https://github.com/opencv/gst-video-analytics/wiki/Model-preparation) how to prepare Tensorflow/Caffe and other models for usage in the inference plugins
### Plugins parameters
[Elements list](https://github.com/opencv/gst-video-analytics/wiki/Elements) and properties list per each element
## How to Contribute
If you have bug fix or an idea to improve the project, please first let us know and submit proposal description to [Issues page](https://github.com/opencv/gst-video-analytics/issues)
as at this stage of the project pull requests not monitored.
---
\* Other names and brands may be claimed as the property of others.
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef CONFIG_H
#define CONFIG_H
#cmakedefine DISABLE_VAAPI
#endif
此差异已折叠。
#!/bin/bash
# ==============================================================================
# Copyright (C) <2018-2019> Intel Corporation
#
# SPDX-License-Identifier: MIT
# ==============================================================================
tag=$1
if [ -z "$tag" ]; then
tag=latest
fi
BASEDIR=$(dirname "$0")
docker build -f ${BASEDIR}/Dockerfile -t gstreamer-plugins:$tag \
--build-arg http_proxy=${HTTP_PROXY} \
--build-arg https_proxy=${HTTPS_PROXY} \
${BASEDIR}/..
#!/bin/bash
# ==============================================================================
# Copyright (C) <2018-2019> Intel Corporation
#
# SPDX-License-Identifier: MIT
# ==============================================================================
set -e
VIDEO_EXAMPLES_PATH=""
INTEL_MODELS_PATH=""
MODELS_PATH=""
IMAGE_NAME="gstreamer-plugins"
for i in "$@"
do
case $i in
-h|--help)
echo "usage: sudo ./run_gstreamer_plugin_container.sh [--video-examples-path=<path>]"
echo "[--intel-models-path=<path>] [--models-path=<path>] [--image-name=<name>]"
exit 0
;;
--video-examples-path=*)
VIDEO_EXAMPLES_PATH="${i#*=}"
shift
;;
--intel-models-path=*)
INTEL_MODELS_PATH="${i#*=}"
shift
;;
--models-path=*)
MODELS_PATH="${i#*=}"
shift
;;
--image-name=*)
IMAGE_NAME="${i#*=}"
shift
;;
*)
# unknown option
;;
esac
done
xhost local:root
docker run -it --privileged --net=host \
-v ~/.Xauthority:/root/.Xauthority \
-v /tmp/.X11-unix/:/tmp/.X11-unix/ \
-e DISPLAY=$DISPLAY \
\
-v $INTEL_MODELS_PATH:/root/intel_models \
-v $MODELS_PATH:/root/models \
-e MODELS_PATH=/root/intel_models:/root/models \
\
-v $VIDEO_EXAMPLES_PATH:/root/video-examples \
-e VIDEO_EXAMPLES_DIR=/root/video-examples \
\
-w /root/gstreamer-plugins/samples \
$IMAGE_NAME
# ==============================================================================
# Copyright (C) <2018-2019> Intel Corporation
#
# SPDX-License-Identifier: MIT
# ==============================================================================
cmake_minimum_required (VERSION 3.1)
add_subdirectory(gst)
# ==============================================================================
# Copyright (C) <2018-2019> Intel Corporation
#
# SPDX-License-Identifier: MIT
# ==============================================================================
cmake_minimum_required (VERSION 3.1)
add_subdirectory(videoanalytics)
# ==============================================================================
# Copyright (C) <2018-2019> Intel Corporation
#
# SPDX-License-Identifier: MIT
# ==============================================================================
find_package(GtkDoc 1.25 REQUIRED)
# Create the target.
gtk_doc_add_module(
${TARGET_NAME}
SOURCE ${CMAKE_CURRENT_SOURCE_DIR}
LIBRARIES ${TARGET_NAME}
)
# Build doc-lib* as part of the default target. Without this, you would
# have to explicitly run something like `make doc-libmeep` to build the docs.
add_custom_target(documentation ALL DEPENDS doc-${TARGET_NAME})
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}/html ${CMAKE_DOCDIR})
# Install the docs. (This assumes you're using the GNUInstallDirs CMake module
# to set the CMAKE_INSTALL_DOCDIR variable correctly).
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}/html
DESTINATION ${CMAKE_DOCDIR})
# ==============================================================================
# Copyright (C) <2018-2019> Intel Corporation
#
# SPDX-License-Identifier: MIT
# ==============================================================================
cmake_minimum_required(VERSION 3.1)
set (TARGET_NAME "gstvideoanalyticsmeta")
find_package(PkgConfig REQUIRED)
pkg_check_modules(GSTREAMER gstreamer-1.0 REQUIRED)
pkg_check_modules(GLIB2 glib-2.0 REQUIRED)
file (GLOB MAIN_SRC
${CMAKE_CURRENT_SOURCE_DIR}/*.c
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)
file (GLOB MAIN_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/*.h
)
add_library(${TARGET_NAME} SHARED ${MAIN_SRC} ${MAIN_HEADERS})
set_target_lib_version(${TARGET_NAME})
set_compile_flags(${TARGET_NAME})
target_include_directories(${TARGET_NAME}
PUBLIC
${GSTREAMER_INCLUDE_DIRS}
${GLIB2_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(${TARGET_NAME}
PUBLIC
${GSTREAMER_LIBRARIES}
${GSTVIDEO_LIBRARIES}
${GLIB2_LIBRARIES}
)
# TODO: perhaps we need to create a function
if(${ENABLE_DOCUMENTATION})
include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeDocs.txt)
endif()
install(TARGETS ${TARGET_NAME} DESTINATION lib/va-gstreamer-plugins)
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include <string.h>
#include "gva_json_meta.h"
#define UNUSED(x) (void)(x)
GType gst_gva_json_meta_api_get_type(void) {
static volatile GType type;
static const gchar *tags[] = {GVA_JSON_META_TAG, NULL};
if (g_once_init_enter(&type)) {
GType _type = gst_meta_api_type_register("GstGVAJSONMetaAPI", tags);
g_once_init_leave(&type, _type);
}
return type;
}
gboolean gst_gva_json_meta_init(GstMeta *meta, gpointer params, GstBuffer *buffer) {
UNUSED(params);
UNUSED(buffer);
GstGVAJSONMeta *json_meta = (GstGVAJSONMeta *)meta;
json_meta->message = 0;
return TRUE;
}
gboolean gst_gva_json_meta_transform(GstBuffer *dest_buf, GstMeta *src_meta, GstBuffer *src_buf, GQuark type,
gpointer data) {
UNUSED(src_buf);
UNUSED(type);
UNUSED(data);
GstGVAJSONMeta *dst = GST_GVA_JSON_META_ADD(dest_buf);
GstGVAJSONMeta *src = (GstGVAJSONMeta *)src_meta;
dst->message = g_strdup(src->message);
return TRUE;
}
void gst_gva_json_meta_free(GstMeta *meta, GstBuffer *buffer) {
UNUSED(buffer);
GstGVAJSONMeta *json_meta = (GstGVAJSONMeta *)meta;
if (json_meta->message) {
g_free(json_meta->message);
json_meta->message = NULL;
}
}
const GstMetaInfo *gst_gva_json_meta_get_info(void) {
static const GstMetaInfo *meta_info = NULL;
if (g_once_init_enter(&meta_info)) {
const GstMetaInfo *meta =
gst_meta_register(gst_gva_json_meta_api_get_type(), "GstGVAJSONMeta", sizeof(GstGVAJSONMeta),
(GstMetaInitFunction)gst_gva_json_meta_init, (GstMetaFreeFunction)gst_gva_json_meta_free,
(GstMetaTransformFunction)gst_gva_json_meta_transform);
g_once_init_leave(&meta_info, meta);
}
return meta_info;
}
gchar *get_json_message(GstGVAJSONMeta *meta) {
return meta->message;
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef __GVA_JSON_INFO_H__
#define __GVA_JSON_INFO_H__
#include <gst/gst.h>
#define GVA_JSON_META_TAG "gva_json_meta"
G_BEGIN_DECLS
typedef struct _GstGVAJSONMeta GstGVAJSONMeta;
struct _GstGVAJSONMeta {
GstMeta meta;
gchar *message;
};
const GstMetaInfo *gst_gva_json_meta_get_info(void);
GType gst_gva_json_meta_api_get_type(void);
#define GST_GVA_JSON_META_INFO (gst_gva_json_meta_get_info())
#define GST_GVA_JSON_META_GET(buf) ((GstGVAJSONMeta *)gst_buffer_get_meta(buf, gst_gva_json_meta_api_get_type()))
#define GST_GVA_JSON_META_ITERATE(buf, state) \
((GstGVAJSONMeta *)gst_buffer_iterate_meta_filtered(buf, state, gst_gva_json_meta_api_get_type()))
#define GST_GVA_JSON_META_ADD(buf) ((GstGVAJSONMeta *)gst_buffer_add_meta(buf, gst_gva_json_meta_get_info(), NULL))
gchar *get_json_message(GstGVAJSONMeta *meta);
G_END_DECLS
#endif /* __GVA_JSON_INFO_H__ */
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#pragma once
#include <gst/gst.h>
#include <gst/video/gstvideometa.h>
#ifdef __cplusplus
extern "C" {
#endif
inline const void *gva_get_tensor_data(GstStructure *s, gsize *nbytes) {
const GValue *f = gst_structure_get_value(s, "data_buffer");
if (!f)
return NULL;
GVariant *v = g_value_get_variant(f);
return g_variant_get_fixed_array(v, nbytes, 1);
}
#ifdef __cplusplus
}
#endif
#define GST_VIDEO_REGION_OF_INTEREST_META_ITERATE(buf, state) \
((GstVideoRegionOfInterestMeta *)_gst_buffer_iterate_meta_filtered(buf, state, \
GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE))
#if defined(GST_VERSION_MAJOR) && (GST_VERSION_MAJOR >= 1 && GST_VERSION_MINOR >= 12)
#define _gst_buffer_iterate_meta_filtered gst_buffer_iterate_meta_filtered
#else
inline GstMeta *_gst_buffer_iterate_meta_filtered(GstBuffer *gst_buffer, gpointer *state_ptr,
GType meta_api_type_filter) {
GstMeta *meta = NULL;
while (meta = gst_buffer_iterate_meta(gst_buffer, state_ptr))
if (meta->info->api == meta_api_type_filter)
break;
return meta;
}
#endif
#ifdef __cplusplus
#include <string>
#include <vector>
namespace GVA {
class Tensor {
public:
enum class Precision { ANY = 0, FP32 = 10, U8 = 40 };
enum class Layout {
ANY = 0,
NCHW = 1,
NHWC = 2,
};
Tensor(GstStructure *s) : s(s) {
}
bool has_field(std::string field_name) {
return gst_structure_has_field(s, field_name.data());
}
std::string get_string(std::string field_name) {
const gchar *val = gst_structure_get_string(s, field_name.data());
return (val) ? std::string(val) : std::string();
}
int get_int(std::string field_name) {
gint val = 0;
gst_structure_get_int(s, field_name.data(), &val);
return val;
}
double get_double(std::string field_name) {
double val = 0;
gst_structure_get_double(s, field_name.data(), &val);
return val;
}
void set_string(std::string field_name, std::string value) {
gst_structure_set(s, field_name.data(), G_TYPE_STRING, value.data(), NULL);
}
void set_int(std::string field_name, int value) {
gst_structure_set(s, field_name.data(), G_TYPE_INT, value, NULL);
}
void set_double(std::string field_name, double value) {
gst_structure_set(s, field_name.data(), G_TYPE_DOUBLE, value, NULL);
}
// Known fields
template <class T>
const std::vector<T> data() {
gsize size = 0;
const void *data = gva_get_tensor_data(s, &size);
if (!data || !size)
return std::vector<T>();
return std::vector<T>((T *)data, (T *)((char *)data + size));
}
std::string name() {
return gst_structure_get_name(s);
}
Precision precision() {
return (Precision)get_int("precision");
}
std::string precision_as_string() {
Precision precision_value = precision();
switch (precision_value) {
case Precision::U8:
return "U8";
case Precision::FP32:
return "FP32";
default:
return "ANY";
}
}
Layout layout() {
return (Layout)get_int("layout");
}
std::string layout_as_string() {
Layout layout_value = layout();
switch (layout_value) {
case Layout::NCHW:
return "NCHW";
case Layout::NHWC:
return "NHWC";
default:
return "ANY";
}
}
std::string layer_name() {
return get_string("layer_name");
}
std::string model_name() {
return get_string("model_name");
}
std::string format() {
return get_string("format");
}
double confidence() {
return get_double("confidence");
}
std::string label() {
return get_string("label");
}
int object_id() {
return get_int("object_id");
}
int label_id() {
return get_int("label_id");
}
GstStructure *gst_structure() {
return s;
}
protected:
GstStructure *s;
};
class RegionOfInterest {
protected:
GstVideoRegionOfInterestMeta *gst_meta;
std::vector<Tensor> tensors;
Tensor *detection;
public:
RegionOfInterest(GstVideoRegionOfInterestMeta *meta) : gst_meta(meta), detection(NULL) {
g_return_if_fail(gst_meta != NULL);
tensors.reserve(g_list_length(meta->params));
for (GList *l = meta->params; l; l = g_list_next(l)) {
GstStructure *s = (GstStructure *)l->data;
tensors.push_back(Tensor(s));
if (tensors.back().name() == "detection") {
detection = &tensors.back();
}
}
}
int number_tensors() {
return tensors.size();
}
Tensor &operator[](int index) {
return tensors[index];
}
GstVideoRegionOfInterestMeta *meta() {
return gst_meta;
}
double confidence() {
return detection ? detection->confidence() : 0;
}
typedef std::vector<Tensor>::iterator iterator;
typedef std::vector<Tensor>::const_iterator const_iterator;
iterator begin() {
return tensors.begin();
}
iterator end() {
return tensors.end();
}
};
class RegionOfInterestList {
protected:
std::vector<RegionOfInterest> objects;
public:
RegionOfInterestList(GstBuffer *buffer) {
GstVideoRegionOfInterestMeta *meta = NULL;
gpointer state = NULL;
while ((meta = GST_VIDEO_REGION_OF_INTEREST_META_ITERATE(buffer, &state))) {
objects.push_back(RegionOfInterest(meta));
}
}
int NumberObjects() {
return objects.size();
}
RegionOfInterest &operator[](int index) {
return objects[index];
}
typedef std::vector<RegionOfInterest>::iterator iterator;
typedef std::vector<RegionOfInterest>::const_iterator const_iterator;
iterator begin() {
return objects.begin();
}
iterator end() {
return objects.end();
}
};
} // namespace GVA
#endif // #ifdef __cplusplus
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include <string.h>
#include "gva_tensor_meta.h"
#define UNUSED(x) (void)(x)
GType gst_gva_tensor_meta_api_get_type(void) {
static volatile GType type;
static const gchar *tags[] = {GVA_TENSOR_META_TAG, NULL};
if (g_once_init_enter(&type)) {
GType _type = gst_meta_api_type_register("GstGVATensorMetaAPI", tags);
g_once_init_leave(&type, _type);
}
return type;
}
gboolean gst_gva_tensor_meta_init(GstMeta *meta, gpointer params, GstBuffer *buffer) {
UNUSED(params);
UNUSED(buffer);
GstGVATensorMeta *tensor_meta = (GstGVATensorMeta *)meta;
tensor_meta->precision = 0;
tensor_meta->rank = 0;
memset(&tensor_meta->dims, 0, sizeof(tensor_meta->dims));
tensor_meta->layout = 0;
tensor_meta->model_name = 0;
tensor_meta->layer_name = 0;
tensor_meta->data = NULL;
tensor_meta->total_bytes = 0;
tensor_meta->element_id = NULL;
return TRUE;
}
gboolean gst_gva_tensor_meta_transform(GstBuffer *dest_buf, GstMeta *src_meta, GstBuffer *src_buf, GQuark type,
gpointer data) {
UNUSED(src_buf);
UNUSED(type);
UNUSED(data);
GstGVATensorMeta *dst = GST_GVA_TENSOR_META_ADD(dest_buf);
GstGVATensorMeta *src = (GstGVATensorMeta *)src_meta;
dst->precision = src->precision;
dst->rank = src->rank;
memcpy(dst->dims, src->dims, sizeof(src->dims));
dst->layout = src->layout;
dst->model_name = g_strdup(src->model_name);
dst->layer_name = g_strdup(src->layer_name);
dst->data = g_slice_copy(src->total_bytes, src->data);
dst->total_bytes = src->total_bytes;
dst->element_id = src->element_id;
return TRUE;
}
void gst_gva_tensor_meta_free(GstMeta *meta, GstBuffer *buffer) {
UNUSED(buffer);
GstGVATensorMeta *tensor_meta = (GstGVATensorMeta *)meta;
if (tensor_meta->model_name) {
g_free(tensor_meta->model_name);
tensor_meta->model_name = NULL;
}
if (tensor_meta->layer_name) {
g_free(tensor_meta->layer_name);
tensor_meta->layer_name = NULL;
}
if (tensor_meta->data) {
g_slice_free1(tensor_meta->total_bytes, tensor_meta->data);
tensor_meta->data = NULL;
tensor_meta->total_bytes = 0;
}
}
const GstMetaInfo *gst_gva_tensor_meta_get_info(void) {
static const GstMetaInfo *meta_info = NULL;
if (g_once_init_enter(&meta_info)) {
const GstMetaInfo *meta = gst_meta_register(
gst_gva_tensor_meta_api_get_type(), "GstGVATensorMeta", sizeof(GstGVATensorMeta),
(GstMetaInitFunction)gst_gva_tensor_meta_init, (GstMetaFreeFunction)gst_gva_tensor_meta_free,
(GstMetaTransformFunction)gst_gva_tensor_meta_transform);
g_once_init_leave(&meta_info, meta);
}
return meta_info;
}
GstGVATensorMeta *find_tensor_meta_ext(GstBuffer *buffer, const char *model_name, const char *output_layer,
const char *element_id) {
GstGVATensorMeta *meta = NULL;
gpointer state = NULL;
if (!model_name && !output_layer && !element_id) {
GST_WARNING("No valid arguments: model_name output_layer element_id");
return NULL;
}
while ((meta = (GstGVATensorMeta *)gst_buffer_iterate_meta(buffer, &state))) {
if (meta->meta.info->api != gst_gva_tensor_meta_api_get_type())
continue;
if (model_name) {
if (!meta->model_name || strstr(meta->model_name, model_name) == 0)
continue;
}
if (output_layer) {
if (!meta->layer_name || strstr(meta->layer_name, output_layer) == 0)
continue;
}
if (element_id) {
if (!meta->element_id || strstr(meta->element_id, element_id) == 0)
continue;
}
return meta;
}
return NULL;
}
GstGVATensorMeta *find_tensor_meta(GstBuffer *buffer, const char *model_name, const char *output_layer) {
return find_tensor_meta_ext(buffer, model_name, output_layer, NULL);
}
/////////////////////////////////////////////////////////////////////////////////////////
guint gva_tensor_number_elements(GstGVATensorMeta *meta) {
return meta->dims[0] ? meta->dims[0] : 1;
}
guint gva_tensor_element_size(GstGVATensorMeta *meta) {
guint size = 1;
for (guint i = 1; i < meta->rank && i < GVA_TENSOR_MAX_RANK; i++) {
if (meta->dims[i])
size *= meta->dims[i];
}
return size;
}
void *gva_tensor_get_element(GstGVATensorMeta *meta, int index) {
int number_elements = gva_tensor_number_elements(meta);
return (int8_t *)meta->data + index * meta->total_bytes / number_elements;
}
guint gva_tensor_size(GstGVATensorMeta *meta) {
guint size = 1;
for (guint i = 0; i < meta->rank && i < GVA_TENSOR_MAX_RANK; i++) {
if (meta->dims[i])
size *= meta->dims[i];
}
return size;
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef __GVA_TENSOR_INFO_H__
#define __GVA_TENSOR_INFO_H__
#include <gst/gst.h>
#define GVA_TENSOR_META_TAG "gva_tensor_meta"
#define GVA_TENSOR_MAX_RANK 8
G_BEGIN_DECLS
/**
* GVAPrecision:
* @UNSPECIFIED: default value
* @FP32: 32bit floating point value
* @U8: unsignned 8bit integer value
*
* Enum value to be used with inference engine APIs to specify precision
*/
typedef enum {
UNSPECIFIED = 255,
FP32 = 10,
U8 = 40,
} GVAPrecision;
/**
* GVALayout:
* @ANY: unspecified layout
* @NCHW: NCWH layout
* @NHWC: NHWC layout
*
* Enum value to be used with inference engine APIs to specify layer laouts
*/
typedef enum {
ANY = 0,
NCHW = 1,
NHWC = 2,
} GVALayout;
typedef struct _GstGVATensorMeta GstGVATensorMeta;
/**
* GstGVATensorMeta:
* @meta: parent meta object
* @precision: tensor precision see (#GVAPrecision)
* @rank: tensor rank
* @dims: array describing tensor's dimensions
* @layout: tensor layout see (#GVALayout)
* @layer_name: tensor output layer name
* @model_name: model name
* @data: tensor data
* @total_bytes: tensor size in bytes
* @element_id: TBD
* @labels: array of strings can be used to assign text attributes to the #GVADetection.
*/
struct _GstGVATensorMeta {
GstMeta meta;
GVAPrecision precision;
guint rank;
size_t dims[GVA_TENSOR_MAX_RANK];
GVALayout layout;
gchar *layer_name;
gchar *model_name;
void *data;
size_t total_bytes;
const gchar *element_id;
};
/**
* gst_gva_tensor_meta_get_info:
* Returns: #GstMetaInfo for the registered meta type
*/
const GstMetaInfo *gst_gva_tensor_meta_get_info(void);
/**
* gst_gva_tensor_meta_api_get_type:
*
* Returns: type for APIs binded to the #GstGVATensorMeta
*/
GType gst_gva_tensor_meta_api_get_type(void);
/**
* gst_gva_tensor_meta_get_info:
*
* Register meta API if needed and
*
* Returns: #GstMetaInfo for registered type
*/
#define GST_GVA_TENSOR_META_INFO (gst_gva_tensor_meta_get_info())
/**
* GST_GVA_TENSOR_META_GET:
* @buf: #GstBuffer where meta will be created
*
* Adds #GstGVATensorMeta to the passed #GstBuffer
*
* Returns: pointer to the create Meta
*/
#define GST_GVA_TENSOR_META_GET(buf) ((GstGVATensorMeta *)gst_buffer_get_meta(buf, gst_gva_tensor_meta_api_get_type()))
/**
* GST_GVA_TENSOR_META_ITERATE:
* @buf: #GstBuffer to iterate through
* @state: variable (of #gpointer type) containing loop state
*
* Helper macro to iterate through all detection metas of #GstBuffer
* |[<!--language="C" -->
* gpointer state = NULL;
* while (meta = GST_GVA_TENSOR_META_ITERATE(buffer, &state)) {
* // ...
* }
*
* Returns: #GstGVATensorMeta
*/
#define GST_GVA_TENSOR_META_ITERATE(buf, state) \
((GstGVATensorMeta *)gst_buffer_iterate_meta_filtered(buf, state, gst_gva_tensor_meta_api_get_type()))
/**
* GST_GVA_TENSOR_META_ADD:
* @buf: #GstBuffer where to create #GstGVATensorMeta
*
* Creates #GstGVATensorMeta and
*
* Returns: pointer to newly created meta
*/
#define GST_GVA_TENSOR_META_ADD(buf) \
((GstGVATensorMeta *)gst_buffer_add_meta(buf, gst_gva_tensor_meta_get_info(), NULL))
/**
* GST_GVA_TENSOR_META_COUNT:
* @buf: #GstBuffer to be processed
*
* Calculate a number of #GstGVATensorMeta in GstBuffer
*
* Returns: number of #GstGVATensorMeta metas
*/
#define GST_GVA_TENSOR_META_COUNT(buf) (gst_buffer_get_n_meta(buf, gst_gva_tensor_meta_api_get_type()))
/**
* find_tensor_meta:
* @buffer: #GstBuffer where it looks for the meta
* @model_name: substring that should be in meta's model_name
* @output_layer: substring that should be in meta's output_layer name
*
* Looks for the tensor meta conforming to passed parameters
*
* Returns: found meta or NULL otherwise
*/
GstGVATensorMeta *find_tensor_meta(GstBuffer *buffer, const char *model_name, const char *output_layer);
/**
* find_tensor_meta_ext:
* @buffer: #GstBuffer where it looks for the meta
* @model_name: substring that should be in meta's model_name
* @output_layer: substring that should be in meta's output_layer name
* @element_id: element_id in meta
* Looks for the tensor meta conforming to passed parameters
*
* Returns: found meta or NULL otherwise
*/
GstGVATensorMeta *find_tensor_meta_ext(GstBuffer *buffer, const char *model_name, const char *output_layer,
const char *element_id);
/**
* gva_tensor_number_elements:
* @meta: #GstGVATensorMeta to get value
*
* Returns: number of elements in tensor
*/
guint gva_tensor_number_elements(GstGVATensorMeta *meta);
/**
* gva_tensor_size:
* @meta: #GstGVATensorMeta to get value
*
* Returns: tensor's size
*/
guint gva_tensor_size(GstGVATensorMeta *meta);
/**
* gva_tensor_element_size:
* @meta: #GstGVATensorMeta to get value
*
* Returns: Size of tensor's element
*/
guint gva_tensor_element_size(GstGVATensorMeta *meta);
/**
* gva_tensor_get_element:
* @meta: #GstGVATensorMeta to get value
* @index: index of element to get
*
* Returns: One element form the tensor by it's index
*/
void *gva_tensor_get_element(GstGVATensorMeta *meta, int index);
G_END_DECLS
/////////////////////////////////////////////////////////////////////////////////////////
// These are functions working with tensors produced by gvaclassify element,
// with tensor first dimension representing number detected objects.
#ifndef __GTK_DOC_IGNORE__
#ifdef __cplusplus
template <typename T>
T *GVATensorGetElement(GstGVATensorMeta *meta, int index) {
int number_elements = gva_tensor_number_elements(meta);
if (index < 0 || index > number_elements)
return nullptr;
if (meta->total_bytes != number_elements * sizeof(T))
return nullptr;
return (T *)((int8_t *)meta->data + index * meta->total_bytes / number_elements);
}
#endif
#endif /* __GTK_DOC_IGNORE__ */
#endif /* __GVA_TENSOR_INFO_H__ */
# ==============================================================================
# Copyright (C) <2018-2019> Intel Corporation
#
# SPDX-License-Identifier: MIT
# ==============================================================================
cmake_minimum_required (VERSION 3.1)
add_subdirectory(common)
add_subdirectory(elements)
if (NOT (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm"))
add_subdirectory(gvaitttracer)
endif()
# ==============================================================================
# Copyright (C) <2018-2019> Intel Corporation
#
# SPDX-License-Identifier: MIT
# ==============================================================================
cmake_minimum_required(VERSION 3.1)
set (TARGET_NAME "common")
find_package(InferenceEngine 1.0 REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GSTREAMER gstreamer-1.0 REQUIRED)
pkg_check_modules(GSTVIDEO gstreamer-video-1.0 REQUIRED)
pkg_check_modules(GLIB2 glib-2.0 REQUIRED)
file (GLOB MAIN_SRC
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/*.c
)
file (GLOB MAIN_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/*.h
)
if (NOT ${DISABLE_VAAPI})
pkg_search_module(VA va libva REQUIRED)
else()
list(REMOVE_ITEM MAIN_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/gst_vaapi_plugins_utils.h)
endif()
add_library(${TARGET_NAME} STATIC ${MAIN_SRC} ${MAIN_HEADERS})
set_compile_flags(${TARGET_NAME})
# FIXME: there are some debug information that are removed for released build type
# FIXME: hence it marked as error
target_compile_options(${TARGET_NAME} PRIVATE -Wno-error=unused-parameter)
target_include_directories(${TARGET_NAME}
PUBLIC
${GSTREAMER_INCLUDE_DIRS}
${GSTVIDEO_INCLUDE_DIRS}
${GLIB2_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(${TARGET_NAME}
PUBLIC
IE::inference_engine
${GSTREAMER_LIBRARIES}
${GSTVIDEO_LIBRARIES}
${GLIB2_LIBRARIES}
logger
gstvideoanalyticsmeta
jsonconvert
)
if (NOT ${DISABLE_VAAPI})
target_include_directories(${TARGET_NAME} PUBLIC ${VA_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} PUBLIC ${VA_LIBRARIES})
endif()
install(TARGETS ${TARGET_NAME} DESTINATION lib/va-gstreamer-plugins)
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "blob2metadata.h"
#include "gva_roi_meta.h"
#include "gva_tensor_meta.h"
#include "meta_converters.h"
#include <inference_engine.hpp>
using namespace InferenceBackend;
int GetUnbatchedSizeInBytes(OutputBlob::Ptr blob, size_t batch_size) {
const std::vector<size_t> &dims = blob->GetDims();
if (dims[0] != batch_size) {
throw std::logic_error("Blob last dimension should be equal to batch size");
}
int size = dims[1];
for (size_t i = 2; i < dims.size(); i++) {
size *= dims[i];
}
switch (blob->GetPrecision()) {
case OutputBlob::Precision::FP32:
size *= sizeof(float);
break;
case OutputBlob::Precision::U8:
break;
}
return size;
}
void Blob2TensorMeta(const std::map<std::string, OutputBlob::Ptr> &output_blobs, std::vector<InferenceFrame> frames,
const gchar *inference_id, const gchar *model_name) {
int batch_size = frames.size();
for (auto blob_iter : output_blobs) {
const char *layer_name = blob_iter.first.c_str();
OutputBlob::Ptr blob = blob_iter.second;
const uint8_t *data = (const uint8_t *)blob->GetData();
auto dims = blob->GetDims();
int size = GetUnbatchedSizeInBytes(blob, batch_size);
for (int b = 0; b < batch_size; b++) {
InferenceFrame &frame = frames[b];
// find or create new meta
GstGVATensorMeta *meta = find_tensor_meta_ext(frame.buffer, model_name, layer_name, inference_id);
if (!meta) {
meta = GST_GVA_TENSOR_META_ADD(frame.buffer);
meta->precision = static_cast<GVAPrecision>((int)blob->GetPrecision());
meta->layout = static_cast<GVALayout>((int)blob->GetLayout());
meta->rank = dims.size();
if (meta->rank > GVA_TENSOR_MAX_RANK)
meta->rank = GVA_TENSOR_MAX_RANK;
for (guint i = 0; i < meta->rank; i++) {
meta->dims[i] = dims[i];
}
meta->layer_name = g_strdup(layer_name);
meta->model_name = g_strdup(model_name);
meta->element_id = inference_id;
meta->total_bytes = size * meta->dims[0];
meta->data = g_slice_alloc0(meta->total_bytes);
}
memcpy(meta->data, data + b * size, size);
}
}
}
void copy_buffer_to_structure(GstStructure *structure, const void *buffer, int size) {
GVariant *v = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, buffer, size, 1);
gsize n_elem;
gst_structure_set(structure, "data_buffer", G_TYPE_VARIANT, v, "data", G_TYPE_POINTER,
g_variant_get_fixed_array(v, &n_elem, 1), NULL);
}
void Blob2RoiMeta(const std::map<std::string, OutputBlob::Ptr> &output_blobs, std::vector<InferenceFrame> frames,
const gchar *inference_id, const gchar *model_name,
const std::map<std::string, GstStructure *> &model_proc) {
int batch_size = frames.size();
for (auto blob_iter : output_blobs) {
std::string layer_name = blob_iter.first;
OutputBlob::Ptr blob = blob_iter.second;
const uint8_t *data = (const uint8_t *)blob->GetData();
int size = GetUnbatchedSizeInBytes(blob, batch_size);
int rank = (int)blob->GetDims().size();
for (int b = 0; b < batch_size; b++) {
// find meta
auto roi = &frames[b].roi;
GstVideoRegionOfInterestMeta *meta = NULL;
gpointer state = NULL;
while ((meta = GST_VIDEO_REGION_OF_INTEREST_META_ITERATE(frames[b].buffer, &state))) {
if (meta->x == roi->x && meta->y == roi->y && meta->w == roi->w && meta->h == roi->h &&
meta->id == roi->id) {
break;
}
}
if (!meta) {
GST_DEBUG("Can't find ROI metadata");
continue;
}
// add new structure to meta
GstStructure *s;
auto proc = model_proc.find(layer_name);
if (proc != model_proc.end()) {
s = gst_structure_copy(proc->second);
} else {
s = gst_structure_new_empty(("layer:" + layer_name).data());
}
gst_structure_set(s, "layer_name", G_TYPE_STRING, layer_name.data(), "model_name", G_TYPE_STRING,
model_name, "element_id", G_TYPE_STRING, inference_id, "precision", G_TYPE_INT,
(int)blob->GetPrecision(), "layout", G_TYPE_INT, (int)blob->GetLayout(), "rank",
G_TYPE_INT, rank, NULL);
copy_buffer_to_structure(s, data + b * size, size);
if (proc != model_proc.end()) {
ConvertMeta(s);
}
gst_video_region_of_interest_meta_add_param(meta, s);
}
}
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#pragma once
#include <gst/gst.h>
#include <gst/gstmeta.h>
#include <gst/video/gstvideofilter.h>
#include <gst/video/video.h>
#include "inference_backend/image_inference.h"
typedef struct {
GstBuffer *buffer;
GstVideoRegionOfInterestMeta roi;
} InferenceFrame;
void Blob2TensorMeta(const std::map<std::string, InferenceBackend::OutputBlob::Ptr> &blobs,
std::vector<InferenceFrame> frames, const gchar *inference_id, const gchar *model_name);
void Blob2RoiMeta(const std::map<std::string, InferenceBackend::OutputBlob::Ptr> &blobs,
std::vector<InferenceFrame> frames, const gchar *inference_id, const gchar *model_name,
const std::map<std::string, GstStructure *> &model_proc);
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "gva_buffer_map.h"
#include "inference_backend/logger.h"
#ifndef DISABLE_VAAPI
#include "gst_vaapi_plugins_utils.h"
#endif
#include <gst/allocators/allocators.h>
#define VA_CALL(_FUNC) \
{ \
ITT_TASK(#_FUNC); \
VAStatus _status = _FUNC; \
if (_status != VA_STATUS_SUCCESS) { \
GST_ERROR(#_FUNC " failed, sts=%d: %s", _status, vaErrorStr(_status)); \
} \
}
inline int gstFormatToFourCC(int format) {
switch (format) {
case GST_VIDEO_FORMAT_NV12:
GST_DEBUG("GST_VIDEO_FORMAT_NV12");
return InferenceBackend::FourCC::FOURCC_NV12;
case GST_VIDEO_FORMAT_BGRx:
GST_DEBUG("GST_VIDEO_FORMAT_BGRx");
return InferenceBackend::FourCC::FOURCC_BGRX;
case GST_VIDEO_FORMAT_BGRA:
GST_DEBUG("GST_VIDEO_FORMAT_BGRA");
return InferenceBackend::FourCC::FOURCC_BGRA;
#if VA_MAJOR_VERSION >= 1
case GST_VIDEO_FORMAT_I420:
GST_DEBUG("GST_VIDEO_FORMAT_I420");
return InferenceBackend::FourCC::FOURCC_I420;
#endif
}
GST_WARNING("Unsupported GST Format: %d.", format);
return 0;
}
bool gva_buffer_map(GstBuffer *buffer, InferenceBackend::Image &image, BufferMapContext &mapContext, GstVideoInfo *info,
InferenceBackend::MemoryType memoryType) {
image = {};
mapContext = {};
image.format = gstFormatToFourCC(info->finfo->format);
image.width = static_cast<int>(info->width);
image.height = static_cast<int>(info->height);
for (int i = 0; i < 4; i++) {
image.stride[i] = info->stride[i];
}
#ifndef DISABLE_VAAPI
GstMemory *mem = gst_buffer_get_memory(buffer, 0);
if (mem && gst_memory_is_type(mem, "GstVaapiVideoMemory")) {
image.type = InferenceBackend::MemoryType::VAAPI;
GstVaapi_GetDisplayAndSurface(buffer, image.va_display, image.va_surface);
if (memoryType == InferenceBackend::MemoryType::SYSTEM) {
void *surface_p;
mapContext.va_display = image.va_display;
VA_CALL(vaDeriveImage(image.va_display, image.va_surface, &mapContext.va_image));
VA_CALL(vaMapBuffer(image.va_display, mapContext.va_image.buf, &surface_p));
for (int i = 0; i < 4; i++) {
image.planes[i] = (uint8_t *)surface_p + info->offset[i];
}
image.type = InferenceBackend::MemoryType::SYSTEM;
}
} else
#endif
{
if (!gst_buffer_map(buffer, &mapContext.gstMapInfo, GST_MAP_READ)) {
GST_ERROR("gva_buffer_map: gst_buffer_map failed\n");
}
for (int i = 0; i < 4; i++) {
image.planes[i] = mapContext.gstMapInfo.data + info->offset[i];
}
}
return true;
}
void gva_buffer_unmap(GstBuffer *buffer, InferenceBackend::Image &, BufferMapContext &mapContext) {
if (mapContext.gstMapInfo.size) {
gst_buffer_unmap(buffer, &mapContext.gstMapInfo);
}
#ifndef DISABLE_VAAPI
if (mapContext.va_display) {
VA_CALL(vaUnmapBuffer(mapContext.va_display, mapContext.va_image.buf));
VA_CALL(vaDestroyImage(mapContext.va_display, mapContext.va_image.image_id));
}
#endif
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "config.h"
#include "inference_backend/image_inference.h"
#include <gst/gstbuffer.h>
#include <gst/video/video-info.h>
#ifndef DISABLE_VAAPI
#include <va/va.h>
#endif
struct BufferMapContext {
GstMapInfo gstMapInfo;
#ifndef DISABLE_VAAPI
VADisplay va_display;
VAImage va_image;
#endif
};
bool gva_buffer_map(GstBuffer *buffer, InferenceBackend::Image &image, BufferMapContext &mapContext, GstVideoInfo *info,
InferenceBackend::MemoryType memoryType);
void gva_buffer_unmap(GstBuffer *buffer, InferenceBackend::Image &image, BufferMapContext &mapContext);
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "gva_utils.h"
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "glib.h"
#include <gst/gst.h>
#ifndef GVA_UTILS_H
#define GVA_UTILS_H
#ifdef __cplusplus
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
__inline std::vector<std::string> SplitString(const std::string input, char delimiter = ',') {
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(input);
while (std::getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
__inline std::string GetStringArrayElem(const std::string &in_str, int index) {
auto tokens = SplitString(in_str);
if (index < 0 || (size_t)index >= tokens.size())
return "";
return tokens[index];
}
__inline std::map<std::string, std::string> String2Map(std::string const &s) {
std::string key, val;
std::istringstream iss(s);
std::map<std::string, std::string> m;
while (std::getline(std::getline(iss, key, '=') >> std::ws, val)) {
m[key] = val;
}
return m;
}
#endif
#endif
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "logger_functions.h"
#include <gst/gst.h>
GST_DEBUG_CATEGORY_STATIC(GVA_common);
#define GST_CAT_DEFAULT GVA_common
void GST_logger(int level, const char *file, const char *function, int line, const char *message) {
static bool is_initialized = false;
if (!is_initialized) {
GST_DEBUG_CATEGORY_INIT(GVA_common, "GVA_common", 0, "debug category for GVA common");
is_initialized = true;
}
// Workaround for GCC poison mark
#ifndef GST_DISABLE_GST_DEBUG
gst_debug_log(GVA_common, static_cast<GstDebugLevel>(level), file, function, line, NULL, "%s", message);
#endif // GST_DISABLE_GST_DEBUG
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#pragma once
#include <gst/gst.h>
void GST_logger(int level, const char *file, const char *function, int line, const char *message);
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "meta_converters.h"
#include "gva_roi_meta.h"
#include <iomanip>
#include <sstream>
#include <string.h>
#include <string>
static void find_max_element_index(const float *array, int len, int *index, float *value) {
*index = 0;
*value = array[0];
for (int i = 1; i < len; i++) {
if (array[i] > *value) {
*index = i;
*value = array[i];
}
}
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
bool Attributes2Text(GstStructure *s) {
const gchar *_method = gst_structure_get_string(s, "method");
std::string method = _method ? _method : "";
bool bMax = method == "max";
bool bCompound = method == "compound";
bool bIndex = method == "index";
if (!bMax && !bCompound && !bIndex)
bMax = true;
gsize nbytes = 0;
const float *data = (const float *)gva_get_tensor_data(s, &nbytes);
if (!data)
return false;
GValueArray *labels = nullptr;
if (!gst_structure_get_array(s, "labels", &labels))
return false;
if (!bIndex) {
if (labels->n_values != (bCompound ? 2 : 1) * nbytes / sizeof(float)) {
g_value_array_free(labels);
return false;
}
}
if (bMax) {
int index;
float confidence;
find_max_element_index(data, labels->n_values, &index, &confidence);
if (data[index] > 0) {
const gchar *label = g_value_get_string(labels->values + index);
gst_structure_set(s, "label", G_TYPE_STRING, label, "label_id", G_TYPE_INT, (gint)index, "confidence",
G_TYPE_DOUBLE, (gdouble)confidence, NULL);
}
} else if (bCompound) {
std::string string;
double threshold = 0.5;
double confidence = 0;
gst_structure_get_double(s, "threshold", &threshold);
for (guint j = 0; j < (labels->n_values) / 2; j++) {
const gchar *label = NULL;
if (data[j] >= threshold) {
label = g_value_get_string(labels->values + j * 2);
} else if (data[j] > 0) {
label = g_value_get_string(labels->values + j * 2 + 1);
}
if (label)
string += label;
if (data[j] >= confidence)
confidence = data[j];
}
gst_structure_set(s, "label", G_TYPE_STRING, string.data(), "confidence", G_TYPE_DOUBLE, (gdouble)confidence,
NULL);
} else if (bIndex) {
std::string string;
int max_value = 0;
for (guint j = 0; j < nbytes / sizeof(float); j++) {
int value = (int)data[j];
if (value < 0 || (guint)value >= labels->n_values)
break;
if (value > max_value)
max_value = value;
string += g_value_get_string(labels->values + value);
}
if (max_value) {
gst_structure_set(s, "label", G_TYPE_STRING, string.data(), NULL);
}
} else {
double threshold = 0.5;
double confidence = 0;
gst_structure_get_double(s, "threshold", &threshold);
for (guint j = 0; j < labels->n_values; j++) {
if (data[j] >= threshold) {
const gchar *label = g_value_get_string(labels->values + j);
gst_structure_set(s, "label", G_TYPE_STRING, label, "confidence", G_TYPE_DOUBLE, (gdouble)confidence,
NULL);
}
if (data[j] >= confidence)
confidence = data[j];
}
}
if (labels)
g_value_array_free(labels);
return true;
}
G_GNUC_END_IGNORE_DEPRECATIONS
bool Tensor2Text(GstStructure *s) {
gsize nbytes = 0;
const float *data = (const float *)gva_get_tensor_data(s, &nbytes);
if (!data)
return false;
gdouble scale = 1.0;
gst_structure_get_double(s, "tensor2text_scale", &scale);
gint precision = 2;
gst_structure_get_int(s, "tensor2text_precision", &precision);
std::stringstream stream;
stream << std::fixed << std::setprecision(precision);
for (size_t i = 0; i < nbytes / sizeof(float); i++) {
if (i)
stream << ", ";
stream << data[i] * scale;
}
gst_structure_set(s, "label", G_TYPE_STRING, stream.str().data(), NULL);
return true;
}
bool ConvertMeta(GstStructure *s) {
const gchar *converter = gst_structure_get_string(s, "converter");
if (!converter)
return false;
if (!strcmp(converter, "attributes")) {
return Attributes2Text(s);
}
if (!strcmp(converter, "tensor2text")) {
return Tensor2Text(s);
}
return false;
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#pragma once
#include <gst/gst.h>
bool ConvertMeta(GstStructure *s);
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "read_model_proc.h"
#include <fstream>
#include <iostream>
#include <json.hpp>
using json = nlohmann::json;
GValue jsonvalue2gvalue(nlohmann::json::reference value) {
GValue gvalue = G_VALUE_INIT;
switch (value.type()) {
case nlohmann::json::value_t::string:
g_value_init(&gvalue, G_TYPE_STRING);
g_value_set_string(&gvalue, ((std::string)value).data());
break;
case nlohmann::json::value_t::boolean:
g_value_init(&gvalue, G_TYPE_BOOLEAN);
g_value_set_boolean(&gvalue, (gboolean)value);
break;
case nlohmann::json::value_t::number_integer:
case nlohmann::json::value_t::number_unsigned:
g_value_init(&gvalue, G_TYPE_INT);
g_value_set_int(&gvalue, (gint)value);
break;
case nlohmann::json::value_t::number_float:
g_value_init(&gvalue, G_TYPE_DOUBLE);
g_value_set_double(&gvalue, (gdouble)value);
break;
case nlohmann::json::value_t::array: {
g_value_init(&gvalue, GST_TYPE_ARRAY);
for (auto &el : value) {
GValue a = jsonvalue2gvalue(el);
gst_value_array_append_value(&gvalue, &a);
g_value_unset(&a);
}
break;
}
case nlohmann::json::value_t::discarded:
case nlohmann::json::value_t::null:
case nlohmann::json::value_t::object:
break;
}
return gvalue;
}
std::map<std::string, GstStructure *> ReadModelProc(std::string filepath) {
std::ifstream input_file(filepath);
json j;
input_file >> j;
input_file.close();
std::map<std::string, GstStructure *> structures;
for (int io = 0; io < 2; io++) {
std::string io_name = io ? "output_postproc" : "input_preproc";
for (auto &proc_item : j[io_name]) {
std::string layer_name = "UNKNOWN";
GstStructure *s = gst_structure_new_empty(layer_name.data());
for (json::iterator it = proc_item.begin(); it != proc_item.end(); ++it) {
std::string key = it.key();
auto value = it.value();
if (key == "attribute_name")
gst_structure_set_name(s, ((std::string)value).data());
if (key == "layer_name")
layer_name = value;
GValue gvalue = jsonvalue2gvalue(value);
gst_structure_set_value(s, key.data(), &gvalue);
g_value_unset(&gvalue);
}
if (!io) {
gst_structure_set(s, "_is_preproc", G_TYPE_BOOLEAN, (gboolean)TRUE, NULL);
}
structures[layer_name] = s;
}
}
return structures;
}
gboolean is_preprocessor(const GstStructure *processor) {
return gst_structure_has_field(processor, "_is_preproc");
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include <gst/gst.h>
#include <map>
#include <string>
std::map<std::string, GstStructure *> ReadModelProc(std::string filepath);
gboolean is_preprocessor(const GstStructure *processor);
# ==============================================================================
# Copyright (C) <2018-2019> Intel Corporation
#
# SPDX-License-Identifier: MIT
# ==============================================================================
cmake_minimum_required (VERSION 3.1)
set (TARGET_NAME "gstvideoanalytics")
find_package(OpenCV REQUIRED core imgproc)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GSTREAMER gstreamer-1.0 REQUIRED)
pkg_check_modules(GSTVIDEO gstreamer-video-1.0 REQUIRED)
pkg_check_modules(GSTALLOC gstreamer-allocators-1.0 REQUIRED)
file (GLOB MAIN_SRC
gvawatermark/*.cpp
gvawatermark/*.c
gvaclassify/*.cpp
gvaidentify/*.c
gvaidentify/*.cpp
gvaclassify/*.c
gvainference/*.cpp
gvainference/*.c
gvametaconvert/*.cpp
gvametaconvert/*.c
elements.c
)
file (GLOB MAIN_HEADERS
gvawatermark/*.h
gvaclassify/*.h
gvaidentify/*.h
gvainference/*.h
gvametaconvert/*.h
)
add_library(${TARGET_NAME} SHARED ${MAIN_SRC} ${MAIN_HEADERS})
set_target_lib_version(${TARGET_NAME})
set_compile_flags(${TARGET_NAME})
# FIXME: there are some debug information that are removed for released build type
# FIXME: hence it marked as error
target_compile_options(${TARGET_NAME} PRIVATE -Wno-error=unused-variable -Wno-error=unused-parameter)
target_include_directories(${TARGET_NAME}
PRIVATE
${GSTREAMER_INCLUDE_DIRS}
${GSTVIDEO_INCLUDE_DIRS}
${GSTALLOC_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}
gvawatermark
gvaclassify
gvaidentify
gvainference
gvametaconvert
)
target_link_libraries(${TARGET_NAME}
PRIVATE
ie_cpu_extension
${OpenCV_LIBS}
${GSTREAMER_LIBRARIES}
${GSTVIDEO_LIBRARIES}
${GSTALLOC_LIBRARIES}
common
image_inference_openvino
pre_proc
opencv_pre_proc
logger
jsonconvert
)
if(NOT ${DISABLE_VAAPI})
target_link_libraries(${TARGET_NAME} PRIVATE vaapi_pre_proc)
endif()
install(TARGETS ${TARGET_NAME} DESTINATION lib/va-gstreamer-plugins)
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstgvaclassify.h"
#include "gstgvaidentify.h"
#include "gstgvainference.h"
#include "gstgvametaconvert.h"
#include "gstgvawatermark.h"
#include <gst/gst.h>
static gboolean plugin_init(GstPlugin *plugin) {
if (!gst_element_register(plugin, "gvainference", GST_RANK_NONE, GST_TYPE_GVA_INFERENCE))
return FALSE;
if (!gst_element_register(plugin, "gvadetect", GST_RANK_NONE, GST_TYPE_GVA_INFERENCE))
return FALSE;
if (!gst_element_register(plugin, "gvaclassify", GST_RANK_NONE, GST_TYPE_GVA_CLASSIFY))
return FALSE;
if (!gst_element_register(plugin, "gvaidentify", GST_RANK_NONE, GST_TYPE_GVA_IDENTIFY))
return FALSE;
if (!gst_element_register(plugin, "gvametaconvert", GST_RANK_NONE, GST_TYPE_GVA_META_CONVERT))
return FALSE;
if (!gst_element_register(plugin, "gvawatermark", GST_RANK_NONE, GST_TYPE_GVA_WATERMARK))
return FALSE;
return TRUE;
}
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR, videoanalytics, "Video Analytics elements", plugin_init,
PLUGIN_VERSION, PLUGIN_LICENSE, PACKAGE_NAME, GST_PACKAGE_ORIGIN)
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "reid_gallery.h"
#include "inference_backend/image_inference.h"
#include <algorithm>
#include <limits>
#include <opencv2/imgproc.hpp>
#include <vector>
cv::Mat GetTransform(cv::Mat *src, cv::Mat *dst) {
cv::Mat col_mean_src;
reduce(*src, col_mean_src, 0, cv::REDUCE_AVG);
for (int i = 0; i < src->rows; i++) {
src->row(i) -= col_mean_src;
}
cv::Mat col_mean_dst;
reduce(*dst, col_mean_dst, 0, cv::REDUCE_AVG);
for (int i = 0; i < dst->rows; i++) {
dst->row(i) -= col_mean_dst;
}
cv::Scalar mean, dev_src, dev_dst;
cv::meanStdDev(*src, mean, dev_src);
dev_src(0) = std::max(static_cast<double>(std::numeric_limits<float>::epsilon()), dev_src(0));
*src /= dev_src(0);
cv::meanStdDev(*dst, mean, dev_dst);
dev_dst(0) = std::max(static_cast<double>(std::numeric_limits<float>::epsilon()), dev_dst(0));
*dst /= dev_dst(0);
cv::Mat w, u, vt;
cv::SVD::compute((*src).t() * (*dst), w, u, vt);
cv::Mat r = (u * vt).t();
cv::Mat m(2, 3, CV_32F);
m.colRange(0, 2) = r * (dev_dst(0) / dev_src(0));
m.col(2) = (col_mean_dst.t() - m.colRange(0, 2) * col_mean_src.t());
return m;
}
void align_rgb_image(InferenceBackend::Image &image, const std::vector<float> &landmarks_points,
const std::vector<float> &reference_points) {
cv::Mat ref_landmarks = cv::Mat(reference_points.size() / 2, 2, CV_32F);
cv::Mat landmarks =
cv::Mat(landmarks_points.size() / 2, 2, CV_32F, const_cast<float *>(&landmarks_points.front())).clone();
for (int i = 0; i < ref_landmarks.rows; i++) {
ref_landmarks.at<float>(i, 0) = reference_points[2 * i] * image.width;
ref_landmarks.at<float>(i, 1) = reference_points[2 * i + 1] * image.height;
landmarks.at<float>(i, 0) *= image.width;
landmarks.at<float>(i, 1) *= image.height;
}
cv::Mat m = GetTransform(&ref_landmarks, &landmarks);
for (int plane_num = 0; plane_num < 4; plane_num++) {
if (image.planes[plane_num]) {
cv::Mat mat0(image.height, image.width, CV_8UC1, image.planes[plane_num], image.stride[plane_num]);
cv::warpAffine(mat0, mat0, m, mat0.size(), cv::WARP_INVERSE_MAP);
}
}
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef __ALIGN_TRANSFORM_H__
#define __ALIGN_TRANSFORM_H__
#include <opencv2/imgproc.hpp>
cv::Mat GetTransform(cv::Mat *src, cv::Mat *dst);
void align_rgb_image(InferenceBackend::Image &image, const std::vector<float> &landmarks_points,
const std::vector<float> &reference_points);
#endif /* __ALIGN_TRANSFORM_H__ */
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "classifyinference.h"
#include <assert.h>
#include <gst/allocators/gstdmabuf.h>
#include <memory>
#include <thread>
#include "config.h"
#include "gva_buffer_map.h"
#include "gva_roi_meta.h"
#include "gva_tensor_meta.h"
#include "gva_utils.h"
#include "inference_backend/image_inference.h"
#include "inference_backend/logger.h"
#include "align_transform.h"
#include "gstgvaclassify.h"
#include "logger_functions.h"
#include "read_model_proc.h"
using namespace std::placeholders;
bool CheckObjectClass(std::string requested, GQuark quark) {
if (requested.empty())
return true;
if (!quark)
return false;
return requested == g_quark_to_string(quark);
}
std::map<std::string, InferenceRefs *> ClassifyInference::inference_pool_;
std::mutex ClassifyInference::inference_pool_mutex_;
ClassifyInferenceProxy *ClassifyInference::aquire_instance(GstGvaClassify *ovino) {
std::lock_guard<std::mutex> guard(inference_pool_mutex_);
std::string name(ovino->inference_id);
InferenceRefs *infRefs = nullptr;
auto it = inference_pool_.find(name);
if (it == inference_pool_.end()) {
infRefs = new InferenceRefs;
infRefs->numRefs++;
infRefs->proxy = new ClassifyInferenceProxy;
if (ovino->model) {
infRefs->proxy->instance = new ClassifyInference(ovino);
// save master element for later reference from slave elements
infRefs->masterElement = ovino;
} else {
// lazy initialization
infRefs->proxy->instance = nullptr;
infRefs->elementsToInit.push_back(ovino);
}
inference_pool_.insert({name, infRefs}); // CHECKME will pair has ref to string or string copy?
} else {
infRefs = it->second;
// always increment ref counter
infRefs->numRefs++;
// if model arg is passed and there is no instance yet
// , we will create it and make available to all element instances
if (!infRefs->proxy->instance && ovino->model) {
infRefs->proxy->instance = new ClassifyInference(ovino);
// save master element for later reference from slave elements
infRefs->masterElement = ovino;
// iterate throught already created elements and set their props
ClassifyInference::initExistingElements(infRefs);
infRefs->elementsToInit.clear();
} else if (infRefs->proxy->instance && !ovino->model) {
// TODO add warning saying that specified props will be ignored if specified for slave.
// Setting missing props to current elem
ClassifyInference::fillElementProps(ovino, infRefs->masterElement);
} else if (infRefs->proxy->instance && ovino->model) {
GST_WARNING_OBJECT(ovino, "Only one element for each inference-id can have other properties specified.");
// TODO implement comprehensive validation if all options match btw slave and master and if not:
// throw std::runtime_error("Only one element for each inference-id can have other properties specified.");
}
}
return infRefs->proxy;
}
void ClassifyInference::release_instance(GstGvaClassify *ovino) {
std::lock_guard<std::mutex> guard(inference_pool_mutex_);
std::string name(ovino->inference_id);
auto it = inference_pool_.find(name);
if (it == inference_pool_.end())
return;
InferenceRefs *infRefs = it->second;
auto refcounter = --infRefs->numRefs;
if (refcounter == 0) {
delete infRefs->proxy->instance;
delete infRefs->proxy;
delete infRefs;
inference_pool_.erase(name);
}
}
void ClassifyInference::fillElementProps(GstGvaClassify *targetElem, GstGvaClassify *masterElem) {
assert(masterElem);
g_free(targetElem->model);
targetElem->model = g_strdup(masterElem->model);
g_free(targetElem->object_class);
targetElem->object_class = g_strdup(masterElem->object_class);
g_free(targetElem->device);
targetElem->device = g_strdup(masterElem->device);
g_free(targetElem->model_proc);
targetElem->model_proc = g_strdup(masterElem->model_proc);
targetElem->batch_size = masterElem->batch_size;
targetElem->every_nth_frame = masterElem->every_nth_frame;
targetElem->nireq = masterElem->nireq;
g_free(targetElem->cpu_extension);
targetElem->cpu_extension = g_strdup(masterElem->cpu_extension);
g_free(targetElem->gpu_extension);
targetElem->gpu_extension = g_strdup(masterElem->gpu_extension);
// no need to copy inference_id because it should match already.
}
void ClassifyInference::initExistingElements(InferenceRefs *infRefs) {
assert(infRefs->masterElement);
for (auto elem : infRefs->elementsToInit) {
ClassifyInference::fillElementProps(elem, infRefs->masterElement);
}
}
ClassifyInferenceProxy *aquire_classify_inference(GstGvaClassify *ovino, GError **error) {
ClassifyInferenceProxy *proxy = nullptr;
try {
proxy = ClassifyInference::aquire_instance(ovino);
} catch (const std::exception &exc) {
g_set_error(error, 1, 1, "%s", exc.what());
}
return proxy;
}
void release_classify_inference(GstGvaClassify *ovino) {
ClassifyInference::release_instance(ovino);
}
void classify_inference_sink_event(GstGvaClassify *ovino, GstEvent *event) {
ovino->inference->instance->SinkEvent(event);
}
GstFlowReturn frame_to_classify_inference(GstGvaClassify *ovino, GstBaseTransform *trans, GstBuffer *buf,
GstVideoInfo *info) {
if (!ovino || !ovino->inference || !ovino->inference->instance) {
GST_ERROR_OBJECT(ovino, "empty inference instance!!!!");
return GST_BASE_TRANSFORM_FLOW_DROPPED;
}
return ovino->inference->instance->TransformFrameIp(ovino, trans, buf, info);
}
void flush_inference_classify(GstGvaClassify *ovino) {
if (!ovino || !ovino->inference || !ovino->inference->instance) {
GST_ERROR_OBJECT(ovino, "empty inference instance!!!!");
return;
}
ovino->inference->instance->FlushInference();
}
ClassifyInference::ClassifyInference(GstGvaClassify *ovino) : frame_num(-1), inference_id(ovino->inference_id) {
std::vector<std::string> model_files;
std::vector<std::string> model_proc;
if (!ovino->model)
throw std::runtime_error("Model not specified");
model_files = SplitString(ovino->model);
if (ovino->model_proc) {
model_proc = SplitString(ovino->model_proc);
}
std::map<std::string, std::string> infer_config;
if (ovino->cpu_extension && *ovino->cpu_extension)
infer_config[InferenceBackend::KEY_CPU_EXTENSION] = ovino->cpu_extension;
if (ovino->cpu_streams && *ovino->cpu_streams) {
std::string cpu_streams = ovino->cpu_streams;
if (cpu_streams == "true")
cpu_streams = std::to_string(ovino->nireq);
if (cpu_streams != "false")
infer_config[InferenceBackend::KEY_CPU_THROUGHPUT_STREAMS] = cpu_streams;
}
for (size_t i = 0; i < model_files.size(); i++) {
std::string &model_file = model_files[i];
GST_WARNING_OBJECT(ovino, "Loading model: device=%s, path=%s", ovino->device, model_file.c_str());
GST_WARNING_OBJECT(ovino, "Setting batch_size=%d, nireq=%d", ovino->batch_size, ovino->nireq);
set_log_function(GST_logger);
auto infer = InferenceBackend::ImageInference::make_shared(
InferenceBackend::MemoryType::ANY, ovino->device, model_file, ovino->batch_size, ovino->nireq, infer_config,
std::bind(&ClassifyInference::InferenceCompletionCallback, this, _1, _2));
ClassificationModel model;
model.inference = infer;
model.model_name = infer->GetModelName();
model.object_class = GetStringArrayElem(ovino->object_class, i);
if (i < model_proc.size() && !model_proc[i].empty()) {
model.model_proc = ReadModelProc(model_proc[i]);
}
model.input_preproc = nullptr;
for (auto proc : model.model_proc) {
if (gst_structure_get_string(proc.second, "converter") && is_preprocessor(proc.second)) {
model.input_preproc = proc.second;
break;
}
}
this->models.push_back(std::move(model));
}
}
void ClassifyInference::FlushInference() {
for (ClassificationModel &model : models) {
model.inference->Flush();
}
}
ClassifyInference::~ClassifyInference() {
for (ClassificationModel &model : models) {
for (auto proc : model.model_proc) {
gst_structure_free(proc.second);
}
}
models.clear();
}
void ClassifyInference::PushOutput() {
while (!output_frames.empty()) {
OutputFrame &front = output_frames.front();
if (front.inference_count > 0) {
break; // inference not completed yet
}
GstBuffer *buffer = front.writable_buffer ? front.writable_buffer : front.buffer;
GstFlowReturn ret = gst_pad_push(GST_BASE_TRANSFORM_SRC_PAD(front.filter), buffer);
if (ret != GST_FLOW_OK) {
GST_WARNING("Inference gst_pad_push returned status %d", ret);
}
output_frames.pop_front();
}
}
GstFlowReturn ClassifyInference::TransformFrameIp(GstGvaClassify *ovino, GstBaseTransform *trans, GstBuffer *buffer,
GstVideoInfo *info) {
std::unique_lock<std::mutex> lock(_mutex);
// Collect all ROI metas into std::vector
std::vector<GstVideoRegionOfInterestMeta *> metas;
GstVideoRegionOfInterestMeta *meta = NULL;
gpointer state = NULL;
while ((meta = GST_VIDEO_REGION_OF_INTEREST_META_ITERATE(buffer, &state))) {
metas.push_back(meta);
}
bool bRunInference = true;
frame_num++;
if (metas.empty() || // ovino->every_nth_frame == -1 || // TODO separate property instead of -1
(ovino->every_nth_frame > 0 && frame_num % ovino->every_nth_frame > 0)) {
bRunInference = false;
}
// count number ROIs to run inference on
int inference_count = 0;
for (ClassificationModel &model : models) {
for (auto meta : metas) {
if (CheckObjectClass(model.object_class, meta->roi_type)) {
inference_count++;
}
}
}
if (inference_count == 0) {
bRunInference = false;
}
if (!bRunInference) {
// If we don't need to run inference and there are no frames queued for inference then finish transform
std::lock_guard<std::mutex> guard(output_frames_mutex);
if (output_frames.empty()) {
return GST_FLOW_OK;
} else {
output_frames.push_back(
{.buffer = gst_buffer_ref(buffer), .writable_buffer = 0, .inference_count = 0, .filter = trans});
return GST_BASE_TRANSFORM_FLOW_DROPPED;
}
}
// increment buffer reference
buffer = gst_buffer_ref(buffer);
// push into output_frames queue
{
std::lock_guard<std::mutex> guard(output_frames_mutex);
output_frames.push_back(
{.buffer = buffer, .writable_buffer = NULL, .inference_count = inference_count, .filter = trans});
}
InferenceBackend::Image image;
BufferMapContext mapContext;
gva_buffer_map(buffer, image, mapContext, info, InferenceBackend::MemoryType::ANY);
for (ClassificationModel &model : models) {
for (auto meta : metas) {
if (!CheckObjectClass(model.object_class, meta->roi_type)) {
continue;
}
image.rect = {.x = (int)meta->x, .y = (int)meta->y, .width = (int)meta->w, .height = (int)meta->h};
auto result = std::make_shared<InferenceResult>();
result->inference_frame.buffer = buffer;
result->inference_frame.roi = *meta;
result->model = &model;
auto preProcessFunction = model.input_preproc && ovino->use_landmarks
? InputPreProcess(image, meta, model.input_preproc)
: [](InferenceBackend::Image &) {};
model.inference->SubmitImage(image, result, preProcessFunction);
}
}
gva_buffer_unmap(buffer, image, mapContext);
// return FLOW_DROPPED as we push buffers from separate thread
return GST_BASE_TRANSFORM_FLOW_DROPPED;
}
void ClassifyInference::SinkEvent(GstEvent *event) {
if (event->type == GST_EVENT_EOS) {
for (ClassificationModel &model : models) {
model.inference->Flush();
}
}
}
void ClassifyInference::InferenceCompletionCallback(
std::map<std::string, InferenceBackend::OutputBlob::Ptr> blobs,
std::vector<std::shared_ptr<InferenceBackend::ImageInference::IFrameBase>> frames) {
if (frames.empty())
return;
std::lock_guard<std::mutex> guard(output_frames_mutex);
std::vector<InferenceFrame> inference_frames;
ClassificationModel *model = nullptr;
for (auto &frame : frames) {
auto f = std::dynamic_pointer_cast<InferenceResult>(frame);
model = f->model;
inference_frames.push_back(f->inference_frame);
GstBuffer *buffer = inference_frames.back().buffer;
// check if we have writable version of this buffer (this function called multiple times on same buffer)
for (OutputFrame &output : output_frames) {
if (output.buffer == buffer) {
if (output.writable_buffer)
buffer = inference_frames.back().buffer = output.writable_buffer;
break;
}
}
// if buffer not writable, make it writable as we need to attach metadata
if (!gst_buffer_is_writable(buffer)) {
GstBuffer *writable_buffer = gst_buffer_make_writable(buffer);
inference_frames.back().buffer = writable_buffer;
// replace buffer pointer in 'output_frames' queue
for (OutputFrame &output_frame : output_frames) {
if (output_frame.buffer == buffer) {
output_frame.writable_buffer = writable_buffer;
break;
}
}
}
}
Blob2RoiMeta(blobs, inference_frames, inference_id.c_str(), model ? model->model_name.c_str() : nullptr,
model->model_proc);
for (InferenceFrame &frame : inference_frames) {
for (OutputFrame &output : output_frames) {
if (frame.buffer == output.buffer || frame.buffer == output.writable_buffer) {
output.inference_count--;
break;
}
}
}
PushOutput();
}
std::function<void(InferenceBackend::Image &)>
ClassifyInference::InputPreProcess(const InferenceBackend::Image &image, GstVideoRegionOfInterestMeta *roi_meta,
GstStructure *preproc) {
const gchar *converter = gst_structure_get_string(preproc, "converter");
if (std::string(converter) == "alignment") {
std::vector<float> reference_points;
std::vector<float> landmarks_points;
// look for tensor data with corresponding format
GVA::RegionOfInterest roi(roi_meta);
for (auto tensor : roi) {
if (tensor.get_string("format") == "landmark_points") {
landmarks_points = tensor.data<float>();
break;
}
}
// load reference points from JSON input_preproc description
GValueArray *alignment_points = nullptr;
if (gst_structure_get_array(preproc, "alignment_points", &alignment_points)) {
for (size_t i = 0; i < alignment_points->n_values; i++) {
reference_points.push_back(g_value_get_double(alignment_points->values + i));
}
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
if (alignment_points)
g_value_array_free(alignment_points);
G_GNUC_END_IGNORE_DEPRECATIONS
if (landmarks_points.size() && landmarks_points.size() == reference_points.size()) {
return [reference_points, landmarks_points](InferenceBackend::Image &picture) {
align_rgb_image(picture, landmarks_points, reference_points);
};
}
}
return [](InferenceBackend::Image &) {};
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef __CLASSIFY_INFERENCE_H__
#define __CLASSIFY_INFERENCE_H__
#include <gst/video/video.h>
struct _GstGvaClassify;
typedef struct _GstGvaClassify GstGvaClassify;
typedef struct _ClassifyInferenceProxy ClassifyInferenceProxy;
#ifdef __cplusplus
#include "blob2metadata.h"
#include "inference_backend/image_inference.h"
#include <list>
#include <mutex>
struct InferenceRefs {
unsigned int numRefs = 0;
std::list<GstGvaClassify *> elementsToInit;
GstGvaClassify *masterElement = nullptr;
ClassifyInferenceProxy *proxy = nullptr;
};
class ClassifyInference {
public:
ClassifyInference(GstGvaClassify *ovino);
static ClassifyInferenceProxy *aquire_instance(GstGvaClassify *ovino);
static void release_instance(GstGvaClassify *ovino);
GstFlowReturn TransformFrameIp(GstGvaClassify *ovino, GstBaseTransform *trans, GstBuffer *buffer,
GstVideoInfo *info);
void SinkEvent(GstEvent *event);
void FlushInference();
~ClassifyInference();
private:
static void fillElementProps(GstGvaClassify *targetElem, GstGvaClassify *masterElem);
static void initExistingElements(InferenceRefs *infRefs);
void PushOutput();
void InferenceCompletionCallback(std::map<std::string, InferenceBackend::OutputBlob::Ptr> blobs,
std::vector<std::shared_ptr<InferenceBackend::ImageInference::IFrameBase>> frames);
std::function<void(InferenceBackend::Image &)> InputPreProcess(const InferenceBackend::Image &image,
GstVideoRegionOfInterestMeta *roi_meta,
GstStructure *preproc);
struct ClassificationModel {
std::string model_name;
std::string object_class;
std::shared_ptr<InferenceBackend::ImageInference> inference;
std::map<std::string, GstStructure *> model_proc;
GstStructure *input_preproc;
};
mutable std::mutex _mutex;
int frame_num;
std::vector<ClassificationModel> models;
static std::map<std::string, InferenceRefs *> inference_pool_;
static std::mutex inference_pool_mutex_;
std::string inference_id;
struct OutputFrame {
GstBuffer *buffer;
GstBuffer *writable_buffer;
int inference_count;
GstBaseTransform *filter;
};
struct InferenceResult : public InferenceBackend::ImageInference::IFrameBase {
InferenceFrame inference_frame;
ClassificationModel *model;
};
std::list<OutputFrame> output_frames;
std::mutex output_frames_mutex;
};
#else /* __cplusplus */
typedef struct ClassifyInference ClassifyInference;
#endif /* __cplusplus */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct _ClassifyInferenceProxy {
ClassifyInference *instance;
};
ClassifyInferenceProxy *aquire_classify_inference(GstGvaClassify *ovino, GError **error);
void release_classify_inference(GstGvaClassify *ovino);
void classify_inference_sink_event(GstGvaClassify *ovino, GstEvent *event);
GstFlowReturn frame_to_classify_inference(GstGvaClassify *ovino, GstBaseTransform *trans, GstBuffer *buf,
GstVideoInfo *info);
void flush_inference_classify(GstGvaClassify *ovino);
#ifdef __cplusplus
} /* extern C */
#endif /* __cplusplus */
#endif /* __CLASSIFY_INFERENCE_H__ */
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "gstgvaclassify.h"
#include <gst/base/gstbasetransform.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#include "config.h"
#define UNUSED(x) (void)(x)
#define ELEMENT_LONG_NAME "Object classification (requires GstVideoRegionOfInterestMeta on input)"
#define ELEMENT_DESCRIPTION "Object classification (requires GstVideoRegionOfInterestMeta on input)"
GST_DEBUG_CATEGORY_STATIC(gst_gva_classify_debug_category);
#define GST_CAT_DEFAULT gst_gva_classify_debug_category
#define DEFAULT_MODEL NULL
#define DEFAULT_INFERENCE_ID NULL
#define DEFAULT_MODEL_PROC NULL
#define DEFAULT_OBJECT_CLASS ""
#define DEFAULT_DEVICE "CPU"
#define DEFAULT_META_FORMAT ""
#define DEFAULT_CPU_EXTENSION ""
#define DEFAULT_GPU_EXTENSION ""
#define DEFAULT_RESIZE_BY_INFERENCE FALSE
#define DEFAULT_MIN_BATCH_SIZE 1
#define DEFAULT_MAX_BATCH_SIZE 1024
#define DEFAULT_BATCH_SIZE 1
#define DEFALUT_MIN_THRESHOLD 0.
#define DEFALUT_MAX_THRESHOLD 1.
#define DEFALUT_THRESHOLD 0.5
#define DEFAULT_MIN_EVERY_NTH_FRAME 1
#define DEFAULT_MAX_EVERY_NTH_FRAME UINT_MAX
#define DEFAULT_EVERY_NTH_FRAME 1
#define DEFAULT_MIN_NIREQ 1
#define DEFAULT_MAX_NIREQ 64
#define DEFAULT_NIREQ 2
#define DEFAULT_CPU_STREAMS ""
#define DEFAULT_USE_LANDMARKS FALSE
static void gst_gva_classify_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
static void gst_gva_classify_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
static void gst_gva_classify_dispose(GObject *object);
static void gst_gva_classify_finalize(GObject *object);
static gboolean gst_gva_classify_set_caps(GstBaseTransform *trans, GstCaps *incaps, GstCaps *outcaps);
static gboolean gst_gva_classify_start(GstBaseTransform *trans);
static gboolean gst_gva_classify_stop(GstBaseTransform *trans);
static gboolean gst_gva_classify_sink_event(GstBaseTransform *trans, GstEvent *event);
static GstFlowReturn gst_gva_classify_transform_ip(GstBaseTransform *trans, GstBuffer *buf);
static void gst_gva_classify_cleanup(GstGvaClassify *gvaclassify);
static void gst_gva_classify_reset(GstGvaClassify *gvaclassify);
static GstStateChangeReturn gst_gva_classify_change_state(GstElement *element, GstStateChange transition);
enum {
PROP_0,
PROP_MODEL,
PROP_OBJECT_CLASS,
PROP_DEVICE,
PROP_BATCH_SIZE,
PROP_EVERY_NTH_FRAME,
PROP_NIREQ,
PROP_CPU_EXTENSION,
PROP_GPU_EXTENSION,
PROP_INFERENCE_ID,
PROP_MODEL_PROC,
PROP_CPU_STREAMS,
PROP_USE_LANDMARKS
};
#ifdef SUPPORT_DMA_BUFFER
#define DMA_BUFFER_CAPS GST_VIDEO_CAPS_MAKE_WITH_FEATURES("memory:DMABuf", "{ I420 }") "; "
#else
#define DMA_BUFFER_CAPS
#endif
#ifndef DISABLE_VAAPI
#define VA_SURFACE_CAPS GST_VIDEO_CAPS_MAKE_WITH_FEATURES("memory:VASurface", "{ NV12 }") "; "
#else
#define VA_SURFACE_CAPS
#endif
#define SYSTEM_MEM_CAPS GST_VIDEO_CAPS_MAKE("{ BGRx, BGRA }")
#define INFERENCE_CAPS DMA_BUFFER_CAPS VA_SURFACE_CAPS SYSTEM_MEM_CAPS
#define VIDEO_SINK_CAPS INFERENCE_CAPS
#define VIDEO_SRC_CAPS INFERENCE_CAPS
/* class initialization */
G_DEFINE_TYPE_WITH_CODE(GstGvaClassify, gst_gva_classify, GST_TYPE_BASE_TRANSFORM,
GST_DEBUG_CATEGORY_INIT(gst_gva_classify_debug_category, "gvaclassify", 0,
"debug category for gvaclassify element"));
static void gst_gva_classify_class_init(GstGvaClassifyClass *klass) {
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
GstBaseTransformClass *base_transform_class = GST_BASE_TRANSFORM_CLASS(klass);
GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
/* Setting up pads and setting metadata should be moved to
base_class_init if you intend to subclass this class. */
gst_element_class_add_pad_template(
element_class, gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, gst_caps_from_string(VIDEO_SRC_CAPS)));
gst_element_class_add_pad_template(element_class, gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
gst_caps_from_string(VIDEO_SINK_CAPS)));
gst_element_class_set_static_metadata(element_class, ELEMENT_LONG_NAME, "Video", ELEMENT_DESCRIPTION,
"Intel Corporation");
gobject_class->set_property = gst_gva_classify_set_property;
gobject_class->get_property = gst_gva_classify_get_property;
gobject_class->dispose = gst_gva_classify_dispose;
gobject_class->finalize = gst_gva_classify_finalize;
base_transform_class->set_caps = GST_DEBUG_FUNCPTR(gst_gva_classify_set_caps);
base_transform_class->start = GST_DEBUG_FUNCPTR(gst_gva_classify_start);
base_transform_class->stop = GST_DEBUG_FUNCPTR(gst_gva_classify_stop);
base_transform_class->sink_event = GST_DEBUG_FUNCPTR(gst_gva_classify_sink_event);
base_transform_class->transform_ip = GST_DEBUG_FUNCPTR(gst_gva_classify_transform_ip);
element_class->change_state = GST_DEBUG_FUNCPTR(gst_gva_classify_change_state);
g_object_class_install_property(gobject_class, PROP_MODEL,
g_param_spec_string("model", "Model", "Inference model file path", DEFAULT_MODEL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(
gobject_class, PROP_INFERENCE_ID,
g_param_spec_string("inference-id", "Inference Id",
"Id for the inference engine to be shared between ovino plugin instances",
DEFAULT_INFERENCE_ID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(
gobject_class, PROP_MODEL_PROC,
g_param_spec_string("model-proc", "Model preproc and postproc",
"JSON file with description of input/output layers pre-processing/post-processing",
DEFAULT_MODEL_PROC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_OBJECT_CLASS,
g_param_spec_string("object-class", "ObjectClass", "Object class",
DEFAULT_OBJECT_CLASS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_DEVICE,
g_param_spec_string("device", "Device", "Inference device plugin CPU or GPU",
DEFAULT_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_CPU_EXTENSION,
g_param_spec_string("cpu-extension", "CpuExtension", "Inference CPU extension",
DEFAULT_CPU_EXTENSION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_GPU_EXTENSION,
g_param_spec_string("gpu-extension", "GpuExtension", "Inference GPU extension",
DEFAULT_GPU_EXTENSION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_BATCH_SIZE,
g_param_spec_uint("batch-size", "Batch size", "number frames for batching",
DEFAULT_MIN_BATCH_SIZE, DEFAULT_MAX_BATCH_SIZE,
DEFAULT_BATCH_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_EVERY_NTH_FRAME,
g_param_spec_uint("every-nth-frame", "EveryNthFrame", "Every Nth frame",
DEFAULT_MIN_EVERY_NTH_FRAME, DEFAULT_MAX_EVERY_NTH_FRAME,
DEFAULT_EVERY_NTH_FRAME,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_NIREQ,
g_param_spec_uint("nireq", "NIReq", "number of inference requests",
DEFAULT_MIN_NIREQ, DEFAULT_MAX_NIREQ, DEFAULT_NIREQ,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(
gobject_class, PROP_USE_LANDMARKS,
g_param_spec_boolean("use-landmarks", "landmarks usage flag", "Controls landmark usage preprocessing stage",
DEFAULT_USE_LANDMARKS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(
gobject_class, PROP_CPU_STREAMS,
g_param_spec_string("cpu-streams", "CPU-Streams",
"Use multiple inference streams/instances for better parallelization and affinity on CPU",
DEFAULT_CPU_STREAMS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void gst_gva_classify_cleanup(GstGvaClassify *gvaclassify) {
if (gvaclassify == NULL)
return;
GST_DEBUG_OBJECT(gvaclassify, "gst_gva_classify_cleanup");
if (gvaclassify->inference) {
release_classify_inference(gvaclassify);
gvaclassify->inference = NULL;
}
g_free(gvaclassify->model);
gvaclassify->model = NULL;
g_free(gvaclassify->object_class);
gvaclassify->device = NULL;
g_free(gvaclassify->device);
gvaclassify->device = NULL;
g_free(gvaclassify->model_proc);
gvaclassify->model_proc = NULL;
g_free(gvaclassify->cpu_extension);
gvaclassify->cpu_extension = NULL;
g_free(gvaclassify->gpu_extension);
gvaclassify->gpu_extension = NULL;
g_free(gvaclassify->inference_id);
gvaclassify->inference_id = NULL;
if (gvaclassify->info) {
gst_video_info_free(gvaclassify->info);
gvaclassify->info = NULL;
}
gvaclassify->initialized = FALSE;
}
static void gst_gva_classify_reset(GstGvaClassify *gvaclassify) {
GST_DEBUG_OBJECT(gvaclassify, "gst_gva_classify_reset");
if (gvaclassify == NULL)
return;
gst_gva_classify_cleanup(gvaclassify);
gvaclassify->model = g_strdup(DEFAULT_MODEL);
gvaclassify->object_class = g_strdup(DEFAULT_OBJECT_CLASS);
gvaclassify->device = g_strdup(DEFAULT_DEVICE);
gvaclassify->model_proc = g_strdup(DEFAULT_MODEL_PROC);
gvaclassify->batch_size = DEFAULT_BATCH_SIZE;
gvaclassify->every_nth_frame = DEFAULT_EVERY_NTH_FRAME;
gvaclassify->nireq = DEFAULT_NIREQ;
gvaclassify->cpu_extension = g_strdup(DEFAULT_CPU_EXTENSION);
gvaclassify->gpu_extension = g_strdup(DEFAULT_GPU_EXTENSION);
gvaclassify->inference_id = g_strdup(DEFAULT_INFERENCE_ID);
gvaclassify->cpu_streams = DEFAULT_CPU_STREAMS;
gvaclassify->inference = NULL;
gvaclassify->initialized = FALSE;
gvaclassify->info = NULL;
gvaclassify->use_landmarks = DEFAULT_USE_LANDMARKS;
}
static GstStateChangeReturn gst_gva_classify_change_state(GstElement *element, GstStateChange transition) {
GstStateChangeReturn ret;
GstGvaClassify *gvaclassify;
gvaclassify = GST_GVA_CLASSIFY(element);
GST_DEBUG_OBJECT(gvaclassify, "gst_gva_classify_change_state");
ret = GST_ELEMENT_CLASS(gst_gva_classify_parent_class)->change_state(element, transition);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_NULL: {
gst_gva_classify_reset(gvaclassify);
break;
}
default:
break;
}
return ret;
}
static void gst_gva_classify_init(GstGvaClassify *gvaclassify) {
GST_DEBUG_OBJECT(gvaclassify, "gst_gva_classify_init");
GST_DEBUG_OBJECT(gvaclassify, "%s", GST_ELEMENT_NAME(GST_ELEMENT(gvaclassify)));
gst_gva_classify_reset(gvaclassify);
}
void gst_gva_classify_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {
GstGvaClassify *gvaclassify = GST_GVA_CLASSIFY(object);
GST_DEBUG_OBJECT(gvaclassify, "set_property");
switch (property_id) {
case PROP_MODEL:
gvaclassify->model = g_value_dup_string(value);
break;
case PROP_OBJECT_CLASS:
gvaclassify->object_class = g_value_dup_string(value);
break;
case PROP_DEVICE:
gvaclassify->device = g_value_dup_string(value);
break;
case PROP_MODEL_PROC:
gvaclassify->model_proc = g_value_dup_string(value);
break;
case PROP_BATCH_SIZE:
gvaclassify->batch_size = g_value_get_uint(value);
break;
case PROP_EVERY_NTH_FRAME:
gvaclassify->every_nth_frame = g_value_get_uint(value);
break;
case PROP_NIREQ:
gvaclassify->nireq = g_value_get_uint(value);
break;
case PROP_CPU_EXTENSION:
gvaclassify->cpu_extension = g_value_dup_string(value);
break;
case PROP_GPU_EXTENSION:
gvaclassify->gpu_extension = g_value_dup_string(value);
break;
case PROP_INFERENCE_ID:
gvaclassify->inference_id = g_value_dup_string(value);
break;
case PROP_CPU_STREAMS:
gvaclassify->cpu_streams = g_value_dup_string(value);
break;
case PROP_USE_LANDMARKS:
gvaclassify->use_landmarks = g_value_get_boolean(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
void gst_gva_classify_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
GstGvaClassify *gvaclassify = GST_GVA_CLASSIFY(object);
GST_DEBUG_OBJECT(gvaclassify, "get_property");
switch (property_id) {
case PROP_MODEL:
g_value_set_string(value, gvaclassify->model);
break;
case PROP_OBJECT_CLASS:
g_value_set_string(value, gvaclassify->object_class);
break;
case PROP_DEVICE:
g_value_set_string(value, gvaclassify->device);
break;
case PROP_MODEL_PROC:
g_value_set_string(value, gvaclassify->model_proc);
break;
case PROP_BATCH_SIZE:
g_value_set_uint(value, gvaclassify->batch_size);
break;
case PROP_EVERY_NTH_FRAME:
g_value_set_uint(value, gvaclassify->every_nth_frame);
break;
case PROP_NIREQ:
g_value_set_uint(value, gvaclassify->nireq);
break;
case PROP_CPU_EXTENSION:
g_value_set_string(value, gvaclassify->cpu_extension);
break;
case PROP_GPU_EXTENSION:
g_value_set_string(value, gvaclassify->gpu_extension);
break;
case PROP_INFERENCE_ID:
g_value_set_string(value, gvaclassify->inference_id);
break;
case PROP_CPU_STREAMS:
g_value_set_string(value, gvaclassify->cpu_streams);
break;
case PROP_USE_LANDMARKS:
g_value_set_boolean(value, gvaclassify->use_landmarks);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
void gst_gva_classify_dispose(GObject *object) {
GstGvaClassify *gvaclassify = GST_GVA_CLASSIFY(object);
GST_DEBUG_OBJECT(gvaclassify, "dispose");
/* clean up as possible. may be called multiple times */
G_OBJECT_CLASS(gst_gva_classify_parent_class)->dispose(object);
}
void gst_gva_classify_finalize(GObject *object) {
GstGvaClassify *gvaclassify = GST_GVA_CLASSIFY(object);
GST_DEBUG_OBJECT(gvaclassify, "finalize");
/* clean up object here */
gst_gva_classify_cleanup(gvaclassify);
G_OBJECT_CLASS(gst_gva_classify_parent_class)->finalize(object);
}
static gboolean gst_gva_classify_set_caps(GstBaseTransform *trans, GstCaps *incaps, GstCaps *outcaps) {
UNUSED(outcaps);
GstGvaClassify *gvaclassify = GST_GVA_CLASSIFY(trans);
GST_DEBUG_OBJECT(gvaclassify, "set_caps");
if (!gvaclassify->info) {
gvaclassify->info = gst_video_info_new();
}
gst_video_info_from_caps(gvaclassify->info, incaps);
return TRUE;
}
/* states */
static gboolean gst_gva_classify_start(GstBaseTransform *trans) {
GstGvaClassify *gvaclassify = GST_GVA_CLASSIFY(trans);
GST_DEBUG_OBJECT(gvaclassify, "start");
if (gvaclassify->initialized)
goto exit;
if (!gvaclassify->inference_id) {
gvaclassify->inference_id = g_strdup(GST_ELEMENT_NAME(GST_ELEMENT(gvaclassify)));
}
GError *error = NULL;
gvaclassify->inference = aquire_classify_inference(gvaclassify, &error);
if (error) {
GST_ELEMENT_ERROR(gvaclassify, RESOURCE, TOO_LAZY, ("gvaclassify plugin intitialization failed"),
("%s", error->message));
g_error_free(error);
goto exit;
}
gvaclassify->initialized = TRUE;
exit:
return gvaclassify->initialized;
}
static gboolean gst_gva_classify_stop(GstBaseTransform *trans) {
GstGvaClassify *gvaclassify = GST_GVA_CLASSIFY(trans);
GST_DEBUG_OBJECT(gvaclassify, "stop");
// FIXME: Hangs when multichannel
// flush_inference_classify(gvaclassify);
return TRUE;
}
static gboolean gst_gva_classify_sink_event(GstBaseTransform *trans, GstEvent *event) {
GstGvaClassify *gvaclassify = GST_GVA_CLASSIFY(trans);
GST_DEBUG_OBJECT(gvaclassify, "sink_event");
classify_inference_sink_event(gvaclassify, event);
return GST_BASE_TRANSFORM_CLASS(gst_gva_classify_parent_class)->sink_event(trans, event);
}
static GstFlowReturn gst_gva_classify_transform_ip(GstBaseTransform *trans, GstBuffer *buf) {
GstGvaClassify *gvaclassify = GST_GVA_CLASSIFY(trans);
GST_DEBUG_OBJECT(gvaclassify, "transform_ip");
if (!gvaclassify->inference->instance) { // TODO find a way to move this check out to initialization stage
GST_ELEMENT_ERROR(gvaclassify, RESOURCE, SETTINGS,
("There is no master element provided for gvaclassify elements with inference-id '%s'. At "
"least one element for each inference-id should have model path specified",
gvaclassify->inference_id),
(NULL));
return GST_FLOW_ERROR;
}
return frame_to_classify_inference(gvaclassify, trans, buf, gvaclassify->info);
/* return GST_FLOW_OK; FIXME shouldn't signal about dropping frames in inplace transform function*/
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef _GST_GVA_CLASSIFY_H_
#define _GST_GVA_CLASSIFY_H_
#include <gst/base/gstbasetransform.h>
#include "classifyinference.h"
G_BEGIN_DECLS
#define GST_TYPE_GVA_CLASSIFY (gst_gva_classify_get_type())
#define GST_GVA_CLASSIFY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GVA_CLASSIFY, GstGvaClassify))
#define GST_GVA_CLASSIFY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_GVA_CLASSIFY, GstGvaClassifyClass))
#define GST_IS_GVA_CLASSIFY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GVA_CLASSIFY))
#define GST_IS_GVA_CLASSIFY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_GVA_CLASSIFY))
typedef struct _GstGvaClassify GstGvaClassify;
typedef struct _GstGvaClassifyClass GstGvaClassifyClass;
struct _GstGvaClassify {
GstBaseTransform base_gvaclassify;
gchar *model;
gchar *object_class;
gchar *model_proc;
gchar *device;
guint batch_size;
guint every_nth_frame;
guint nireq;
gchar *cpu_extension;
gchar *gpu_extension;
gchar *inference_id;
gboolean initialized;
gchar *cpu_streams;
GstVideoInfo *info;
gboolean use_landmarks;
ClassifyInferenceProxy *inference;
};
struct _GstGvaClassifyClass {
GstBaseTransformClass base_gvaclassify_class;
};
GType gst_gva_classify_get_type(void);
G_END_DECLS
#endif
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "gstgvaidentify.h"
#include <gst/base/gstbasetransform.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#include "config.h"
#define UNUSED(x) (void)(x)
#define ELEMENT_LONG_NAME \
"Object/face recognition: match re-identification feature vector against registered feature vectors"
#define ELEMENT_DESCRIPTION \
"Object/face recognition: match re-identification feature vector against registered feature vectors"
GST_DEBUG_CATEGORY_STATIC(gst_gva_identify_debug_category);
#define GST_CAT_DEFAULT gst_gva_identify_debug_category
#define DEFAULT_MODEL NULL
#define DEFAULT_GALLERY ""
#define DEFAULT_META_FORMAT ""
#define DEFAULT_MIN_THRESHOLD 0.
#define DEFAULT_MAX_THRESHOLD 1.
#define DEFAULT_THRESHOLD 0.7
#define DEFAULT_TRACKER FALSE
static void gst_gva_identify_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
static void gst_gva_identify_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
static void gst_gva_identify_dispose(GObject *object);
static void gst_gva_identify_finalize(GObject *object);
static gboolean gst_gva_identify_set_caps(GstBaseTransform *trans, GstCaps *incaps, GstCaps *outcaps);
static gboolean gst_gva_identify_start(GstBaseTransform *trans);
static gboolean gst_gva_identify_stop(GstBaseTransform *trans);
static gboolean gst_gva_identify_sink_event(GstBaseTransform *trans, GstEvent *event);
static GstFlowReturn gst_gva_identify_transform_ip(GstBaseTransform *trans, GstBuffer *buf);
static void gst_gva_identify_cleanup(GstGvaIdentify *gvaidentify);
static void gst_gva_identify_reset(GstGvaIdentify *gvaidentify);
static GstStateChangeReturn gst_gva_identify_change_state(GstElement *element, GstStateChange transition);
enum { PROP_0, PROP_MODEL, PROP_GALLERY, PROP_THRESHOLD, PROP_TRACKER };
#ifdef SUPPORT_DMA_BUFFER
#define DMA_BUFFER_CAPS GST_VIDEO_CAPS_MAKE_WITH_FEATURES("memory:DMABuf", "{ I420 }") "; "
#else
#define DMA_BUFFER_CAPS
#endif
#ifndef DISABLE_VAAPI
#define VA_SURFACE_CAPS GST_VIDEO_CAPS_MAKE_WITH_FEATURES("memory:VASurface", "{ NV12 }") "; "
#else
#define VA_SURFACE_CAPS
#endif
#define SYSTEM_MEM_CAPS GST_VIDEO_CAPS_MAKE("{ BGRx, BGRA }")
#define INFERENCE_CAPS DMA_BUFFER_CAPS VA_SURFACE_CAPS SYSTEM_MEM_CAPS
#define VIDEO_SINK_CAPS INFERENCE_CAPS
#define VIDEO_SRC_CAPS INFERENCE_CAPS
/* class initialization */
G_DEFINE_TYPE_WITH_CODE(GstGvaIdentify, gst_gva_identify, GST_TYPE_BASE_TRANSFORM,
GST_DEBUG_CATEGORY_INIT(gst_gva_identify_debug_category, "gvaidentify", 0,
"debug category for gvaidentify element"));
static void gst_gva_identify_class_init(GstGvaIdentifyClass *klass) {
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
GstBaseTransformClass *base_transform_class = GST_BASE_TRANSFORM_CLASS(klass);
GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
/* Setting up pads and setting metadata should be moved to
base_class_init if you intend to subclass this class. */
gst_element_class_add_pad_template(
element_class, gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, gst_caps_from_string(VIDEO_SRC_CAPS)));
gst_element_class_add_pad_template(element_class, gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
gst_caps_from_string(VIDEO_SINK_CAPS)));
gst_element_class_set_static_metadata(element_class, ELEMENT_LONG_NAME, "Video", ELEMENT_DESCRIPTION,
"Intel Corporation");
gobject_class->set_property = gst_gva_identify_set_property;
gobject_class->get_property = gst_gva_identify_get_property;
gobject_class->dispose = gst_gva_identify_dispose;
gobject_class->finalize = gst_gva_identify_finalize;
base_transform_class->set_caps = GST_DEBUG_FUNCPTR(gst_gva_identify_set_caps);
base_transform_class->start = GST_DEBUG_FUNCPTR(gst_gva_identify_start);
base_transform_class->stop = GST_DEBUG_FUNCPTR(gst_gva_identify_stop);
base_transform_class->sink_event = GST_DEBUG_FUNCPTR(gst_gva_identify_sink_event);
base_transform_class->transform_ip = GST_DEBUG_FUNCPTR(gst_gva_identify_transform_ip);
element_class->change_state = GST_DEBUG_FUNCPTR(gst_gva_identify_change_state);
g_object_class_install_property(gobject_class, PROP_MODEL,
g_param_spec_string("model", "Model", "Inference model file path", DEFAULT_MODEL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_GALLERY,
g_param_spec_string("gallery", "Gallery",
"JSON file with list of image examples for each known "
"object/face/person. See samples for JSON format examples",
DEFAULT_GALLERY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_TRACKER,
g_param_spec_boolean("tracker", "Tracker",
"Enable position-based object tracker. "
"The tracker assigns object_id to all tracked objects and "
"smooths identification results over period of time",
DEFAULT_TRACKER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_THRESHOLD,
g_param_spec_float("threshold", "Threshold",
"Identification threshold"
"for object comparison versus objects in the gallery",
DEFAULT_MIN_THRESHOLD, DEFAULT_MAX_THRESHOLD, DEFAULT_THRESHOLD,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void gst_gva_identify_cleanup(GstGvaIdentify *gvaidentify) {
if (gvaidentify == NULL)
return;
GST_DEBUG_OBJECT(gvaidentify, "gst_gva_identify_cleanup");
if (gvaidentify->identifier) {
identifier_delete(gvaidentify->identifier);
gvaidentify->identifier = NULL;
}
g_free(gvaidentify->model);
gvaidentify->model = NULL;
g_free(gvaidentify->gallery);
gvaidentify->gallery = NULL;
gvaidentify->initialized = FALSE;
}
static void gst_gva_identify_reset(GstGvaIdentify *gvaidentify) {
GST_DEBUG_OBJECT(gvaidentify, "gst_gva_identify_reset");
if (gvaidentify == NULL)
return;
gst_gva_identify_cleanup(gvaidentify);
gvaidentify->model = g_strdup(DEFAULT_MODEL);
gvaidentify->gallery = g_strdup(DEFAULT_GALLERY);
gvaidentify->tracker = DEFAULT_TRACKER;
gvaidentify->threshold = DEFAULT_THRESHOLD;
gvaidentify->identifier = NULL;
gvaidentify->initialized = FALSE;
}
static GstStateChangeReturn gst_gva_identify_change_state(GstElement *element, GstStateChange transition) {
GstStateChangeReturn ret;
GstGvaIdentify *gvaidentify;
gvaidentify = GST_GVA_IDENTIFY(element);
GST_DEBUG_OBJECT(gvaidentify, "gst_gva_identify_change_state");
ret = GST_ELEMENT_CLASS(gst_gva_identify_parent_class)->change_state(element, transition);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_NULL: {
gst_gva_identify_reset(gvaidentify);
break;
}
default:
break;
}
return ret;
}
static void gst_gva_identify_init(GstGvaIdentify *gvaidentify) {
GST_DEBUG_OBJECT(gvaidentify, "gst_gva_identify_init");
GST_DEBUG_OBJECT(gvaidentify, "%s", GST_ELEMENT_NAME(GST_ELEMENT(gvaidentify)));
gst_gva_identify_reset(gvaidentify);
}
void gst_gva_identify_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {
GstGvaIdentify *gvaidentify = GST_GVA_IDENTIFY(object);
GST_DEBUG_OBJECT(gvaidentify, "set_property");
switch (property_id) {
case PROP_MODEL:
gvaidentify->model = g_value_dup_string(value);
break;
case PROP_GALLERY:
gvaidentify->gallery = g_value_dup_string(value);
break;
case PROP_TRACKER:
gvaidentify->tracker = g_value_get_boolean(value);
break;
case PROP_THRESHOLD:
gvaidentify->threshold = g_value_get_float(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
void gst_gva_identify_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
GstGvaIdentify *gvaidentify = GST_GVA_IDENTIFY(object);
GST_DEBUG_OBJECT(gvaidentify, "get_property");
switch (property_id) {
case PROP_MODEL:
g_value_set_string(value, gvaidentify->model);
break;
case PROP_THRESHOLD:
g_value_set_float(value, gvaidentify->threshold);
break;
case PROP_GALLERY:
g_value_set_string(value, gvaidentify->gallery);
break;
case PROP_TRACKER:
g_value_set_boolean(value, gvaidentify->tracker);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
void gst_gva_identify_dispose(GObject *object) {
GstGvaIdentify *gvaidentify = GST_GVA_IDENTIFY(object);
GST_DEBUG_OBJECT(gvaidentify, "dispose");
/* clean up as possible. may be called multiple times */
G_OBJECT_CLASS(gst_gva_identify_parent_class)->dispose(object);
}
void gst_gva_identify_finalize(GObject *object) {
GstGvaIdentify *gvaidentify = GST_GVA_IDENTIFY(object);
GST_DEBUG_OBJECT(gvaidentify, "finalize");
/* clean up object here */
gst_gva_identify_cleanup(gvaidentify);
G_OBJECT_CLASS(gst_gva_identify_parent_class)->finalize(object);
}
static gboolean gst_gva_identify_set_caps(GstBaseTransform *trans, GstCaps *incaps, GstCaps *outcaps) {
UNUSED(outcaps);
GstGvaIdentify *gvaidentify = GST_GVA_IDENTIFY(trans);
GST_DEBUG_OBJECT(gvaidentify, "set_caps");
if (!gvaidentify->info) {
gvaidentify->info = gst_video_info_new();
}
gst_video_info_from_caps(gvaidentify->info, incaps);
return TRUE;
}
/* states */
static gboolean gst_gva_identify_start(GstBaseTransform *trans) {
GstGvaIdentify *gvaidentify = GST_GVA_IDENTIFY(trans);
GST_DEBUG_OBJECT(gvaidentify, "start");
if (gvaidentify->initialized)
goto exit;
if (!gvaidentify->identifier) {
gvaidentify->identifier = identifier_new(gvaidentify);
}
gvaidentify->initialized = TRUE;
exit:
return gvaidentify->initialized;
}
static gboolean gst_gva_identify_stop(GstBaseTransform *trans) {
GstGvaIdentify *gvaidentify = GST_GVA_IDENTIFY(trans);
GST_DEBUG_OBJECT(gvaidentify, "stop");
return TRUE;
}
static gboolean gst_gva_identify_sink_event(GstBaseTransform *trans, GstEvent *event) {
GstGvaIdentify *gvaidentify = GST_GVA_IDENTIFY(trans);
GST_DEBUG_OBJECT(gvaidentify, "sink_event");
return GST_BASE_TRANSFORM_CLASS(gst_gva_identify_parent_class)->sink_event(trans, event);
}
static GstFlowReturn gst_gva_identify_transform_ip(GstBaseTransform *trans, GstBuffer *buf) {
GstGvaIdentify *gvaidentify = GST_GVA_IDENTIFY(trans);
GST_DEBUG_OBJECT(gvaidentify, "transform_ip");
return frame_to_identify(gvaidentify, buf, gvaidentify->info);
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef _GST_GVA_IDENTIFY_H_
#define _GST_GVA_IDENTIFY_H_
#include <gst/base/gstbasetransform.h>
#include "identify.h"
G_BEGIN_DECLS
#define GST_TYPE_GVA_IDENTIFY (gst_gva_identify_get_type())
#define GST_GVA_IDENTIFY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GVA_IDENTIFY, GstGvaIdentify))
#define GST_GVA_IDENTIFY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_GVA_IDENTIFY, GstGvaIdentifyClass))
#define GST_IS_GVA_IDENTIFY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GVA_IDENTIFY))
#define GST_IS_GVA_IDENTIFY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_GVA_IDENTIFY))
typedef struct _GstGvaIdentify GstGvaIdentify;
typedef struct _GstGvaIdentifyClass GstGvaIdentifyClass;
struct _GstGvaIdentify {
GstBaseTransform base_gvaidentify;
gchar *model;
gchar *gallery;
gboolean initialized;
gboolean tracker;
gdouble threshold;
GstVideoInfo *info;
Identify *identifier;
};
struct _GstGvaIdentifyClass {
GstBaseTransformClass base_gvaidentify_class;
};
GType gst_gva_identify_get_type(void);
G_END_DECLS
#endif
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "identify.h"
#include "config.h"
#include "gstgvaidentify.h"
#include "gva_roi_meta.h"
#include "gva_tensor_meta.h"
#include "gva_utils.h"
#include <opencv2/imgproc.hpp>
#include <vector>
#include "logger_functions.h"
#define UNUSED(x) (void)x
using namespace std::placeholders;
Identify::Identify(GstGvaIdentify *ovino) : frame_num(0) {
masterGstElement_ = ovino;
// Create gallery
double reid_threshold = ovino->threshold;
gallery = std::unique_ptr<EmbeddingsGallery>(new EmbeddingsGallery(ovino->gallery, reid_threshold));
// Create tracker. TODO expose some of parameters as GST properties
if (ovino->tracker) {
TrackerParams tracker_reid_params;
tracker_reid_params.min_track_duration = 1;
tracker_reid_params.forget_delay = 150;
tracker_reid_params.affinity_thr = 0.8;
tracker_reid_params.averaging_window_size = 1;
tracker_reid_params.bbox_heights_range = cv::Vec2f(10, 1080);
tracker_reid_params.drop_forgotten_tracks = false;
tracker_reid_params.max_num_objects_in_track = std::numeric_limits<int>::max();
tracker_reid_params.objects_type = "face";
tracker = std::unique_ptr<Tracker>(new Tracker(tracker_reid_params));
} else {
tracker = nullptr;
}
}
Identify::~Identify() {
}
void Identify::ProcessOutput(GstBuffer *buffer, GstVideoInfo *info) {
GVA::RegionOfInterestList roi_list(buffer);
std::vector<GVA::Tensor *> tensors;
std::vector<cv::Mat> embeddings;
std::vector<TrackedObject> tracked_objects;
// Compare embeddings versus gallery
for (GVA::RegionOfInterest &roi : roi_list) {
for (GVA::Tensor &tensor : roi) {
auto s = tensor.model_name();
if (masterGstElement_->model) {
if (tensor.model_name().find(masterGstElement_->model) == std::string::npos)
continue;
} else {
if (tensor.format() != "cosine_distance")
continue;
}
// embeddings
std::vector<float> data = tensor.data<float>();
cv::Mat blob_wrapper(data.size(), 1, CV_32F, data.data());
embeddings.emplace_back();
blob_wrapper.copyTo(embeddings.back());
// tracked_objects
GstVideoRegionOfInterestMeta *meta = roi.meta();
cv::Rect rect(meta->x, meta->y, meta->w, meta->h);
tracked_objects.emplace_back(rect, roi.confidence(), 0, 0);
// tensors
tensors.push_back(&tensor);
break;
}
}
auto ids = gallery->GetIDsByEmbeddings(embeddings);
// set object_index and label
for (size_t i = 0; i < tracked_objects.size(); i++) {
int label = ids.empty() ? EmbeddingsGallery::unknown_id : ids[i];
tracked_objects[i].label = label;
tracked_objects[i].object_index = i;
}
// Run tracker
if (tracker) {
frame_num++;
tracker->Process(cv::Size(info->width, info->height), tracked_objects, frame_num);
tracked_objects = tracker->TrackedDetections();
}
// Add object_id and label_id to metadata
for (TrackedObject &obj : tracked_objects) {
if (obj.object_index < 0 || (size_t)obj.object_index >= tensors.size())
continue;
GVA::Tensor *tensor = tensors[obj.object_index];
tensor->set_string("label", gallery->GetLabelByID(obj.label));
tensor->set_double("confidence", obj.confidence);
tensor->set_int("label_id", obj.label + 1); // 0=Unrecognized object, recognized objects starting value 1
tensor->set_int("object_id", obj.object_id);
}
}
GstFlowReturn frame_to_identify(GstGvaIdentify *ovino, GstBuffer *buf, GstVideoInfo *info) {
ovino->identifier->ProcessOutput(buf, info);
return GST_FLOW_OK;
}
Identify *identifier_new(GstGvaIdentify *ovino) {
return new Identify(ovino);
}
void identifier_delete(Identify *identifier) {
delete identifier;
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef __IDENTIFY_INFERENCE_H__
#define __IDENTIFY_INFERENCE_H__
#include <gst/video/video.h>
struct _GstGvaIdentify;
typedef struct _GstGvaIdentify GstGvaIdentify;
#ifdef __cplusplus
#include "blob2metadata.h"
#include "inference_backend/image_inference.h"
#include "reid_gallery.h"
#include "tracker.h"
class Identify {
public:
Identify(GstGvaIdentify *ovino);
~Identify();
void ProcessOutput(GstBuffer *buffer, GstVideoInfo *info);
private:
int frame_num;
std::unique_ptr<Tracker> tracker;
std::unique_ptr<EmbeddingsGallery> gallery;
GstGvaIdentify *masterGstElement_;
};
#else /* __cplusplus */
typedef struct Identify Identify;
#endif /* __cplusplus */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
GstFlowReturn frame_to_identify(GstGvaIdentify *ovino, GstBuffer *buf, GstVideoInfo *info);
Identify *identifier_new(GstGvaIdentify *ovino);
void identifier_delete(Identify *identifier);
#ifdef __cplusplus
} /* extern C */
#endif /* __cplusplus */
#endif /* __IDENTIFY_INFERENCE_H__ */
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#include "reid_gallery.h"
#include "tracker.h"
#include <fstream>
#include <iostream>
#include <limits>
#include <stdio.h>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
namespace {
float ComputeReidDistance(const cv::Mat &descr1, const cv::Mat &descr2) {
float xx = descr1.dot(descr1);
float yy = descr2.dot(descr2);
float xy = descr1.dot(descr2);
float norm = sqrt(xx * yy) + 1e-6;
return 1.0f - xy / norm;
}
bool file_exists(const std::string &name) {
std::ifstream f(name.c_str());
return f.good();
}
inline char separator() {
#ifdef _WIN32
return '\\';
#else
return '/';
#endif
}
std::string folder_name(const std::string &path) {
size_t found_pos;
found_pos = path.find_last_of(separator());
if (found_pos != std::string::npos)
return path.substr(0, found_pos);
return std::string(".") + separator();
}
} // namespace
const std::string EmbeddingsGallery::unknown_label = "Unknown";
const int EmbeddingsGallery::unknown_id = TrackedObject::UNKNOWN_LABEL_IDX;
EmbeddingsGallery::EmbeddingsGallery(const std::string &ids_list, double threshold) : reid_threshold(threshold) {
if (ids_list.empty()) {
std::cout << "Warning: face reid gallery is empty!"
<< "\n";
return;
}
cv::FileStorage fs(ids_list, cv::FileStorage::Mode::READ);
cv::FileNode fn = fs.root();
int id = 0;
for (cv::FileNodeIterator fit = fn.begin(); fit != fn.end(); ++fit) {
cv::FileNode item = *fit;
std::string label = item.name();
std::vector<cv::Mat> features;
if (!item.isMap()) {
std::cout << "Warning: wrong json format. " << label << " is not a mapping" << std::endl;
continue;
}
cv::FileNode features_item = item["features"];
if (features_item.isNone()) {
std::cout << "Warning: no features for label: " << label << std::endl;
continue;
}
for (size_t i = 0; i < features_item.size(); i++) {
std::string path;
if (file_exists(features_item[i].string())) {
path = features_item[i].string();
} else {
path = folder_name(ids_list) + separator() + features_item[i].string();
}
std::ifstream input(path, std::ifstream::binary);
if (input) {
input.seekg(0, input.end);
int file_size = input.tellg();
input.seekg(0, input.beg);
cv::Mat emb(file_size / sizeof(float), 1, CV_32F);
input.read((char *)emb.data, file_size);
features.push_back(emb);
idx_to_id.push_back(id); // this line fixed. Was: (total_images)
} else {
std::cout << "Warning: Failed to open feature file: " << path << std::endl;
}
}
identities.emplace_back(features, label, id);
++id;
}
}
std::vector<int> EmbeddingsGallery::GetIDsByEmbeddings(const std::vector<cv::Mat> &embeddings) const {
if (embeddings.empty() || idx_to_id.empty())
return std::vector<int>();
cv::Mat distances(static_cast<int>(embeddings.size()), static_cast<int>(idx_to_id.size()), CV_32F);
for (int i = 0; i < distances.rows; i++) {
int k = 0;
for (size_t j = 0; j < identities.size(); j++) {
for (const auto &reference_emb : identities[j].embeddings) {
distances.at<float>(i, k) = ComputeReidDistance(embeddings[i], reference_emb);
k++;
}
}
}
KuhnMunkres matcher;
auto matched_idx = matcher.Solve(distances);
std::vector<int> output_ids;
for (auto col_idx : matched_idx) {
if (distances.at<float>(output_ids.size(), col_idx) > reid_threshold)
output_ids.push_back(unknown_id);
else
output_ids.push_back(idx_to_id[col_idx]);
}
return output_ids;
}
std::string EmbeddingsGallery::GetLabelByID(int id) const {
if (id >= 0 && id < static_cast<int>(identities.size()))
return identities[id].label;
else
return unknown_label;
}
size_t EmbeddingsGallery::size() const {
return identities.size();
}
std::vector<std::string> EmbeddingsGallery::GetIDToLabelMap() const {
std::vector<std::string> map;
map.reserve(identities.size());
for (const auto &item : identities) {
map.emplace_back(item.label);
}
return map;
}
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#pragma once
#include <map>
#include <string>
#include <vector>
#include <opencv2/core/core.hpp>
#define GALLERY_MAGIC_VALUE 0x47166923
struct GalleryObject {
std::vector<cv::Mat> embeddings;
std::string label;
int id;
GalleryObject(const std::vector<cv::Mat> &embeddings, const std::string &label, int id)
: embeddings(embeddings), label(label), id(id) {
}
};
class EmbeddingsGallery {
public:
static const std::string unknown_label;
static const int unknown_id;
EmbeddingsGallery(const std::string &ids_list, double threshold);
size_t size() const;
std::vector<int> GetIDsByEmbeddings(const std::vector<cv::Mat> &embeddings) const;
std::string GetLabelByID(int id) const;
std::vector<std::string> GetIDToLabelMap() const;
private:
std::vector<int> idx_to_id;
double reid_threshold;
std::vector<GalleryObject> identities;
};
此差异已折叠。
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#pragma once
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>
#include <opencv2/core/core.hpp>
struct TrackedObject {
cv::Rect rect;
float confidence;
int label; // either id of a label, or UNKNOWN_LABEL_IDX
int object_index;
int object_id;
static const int UNKNOWN_LABEL_IDX; // the value (-1) for unknown label
int frame_idx; ///< Frame index where object was detected (-1 if N/A).
TrackedObject(const cv::Rect &rect = cv::Rect(), float conf = -1.0f, int label = -1, int object_index = -1,
int object_id = -1)
: rect(rect), confidence(conf), label(label), object_index(object_index), object_id(object_id), frame_idx(-1) {
}
};
using TrackedObjects = std::vector<TrackedObject>;
///
/// \brief The KuhnMunkres class
///
/// Solves the assignment problem.
///
class KuhnMunkres {
public:
KuhnMunkres();
///
/// \brief Solves the assignment problem for given dissimilarity matrix.
/// It returns a vector that where each element is a column index for
/// corresponding row (e.g. result[0] stores optimal column index for very
/// first row in the dissimilarity matrix).
/// \param dissimilarity_matrix CV_32F dissimilarity matrix.
/// \return Optimal column index for each row. -1 means that there is no
/// column for row.
///
std::vector<size_t> Solve(const cv::Mat &dissimilarity_matrix);
private:
class Impl;
std::shared_ptr<Impl> impl_; ///< Class implementation.
};
///
/// \brief The Params struct stores parameters of Tracker.
///
struct TrackerParams {
size_t min_track_duration; ///< Min track duration in frames
size_t forget_delay; ///< Forget about track if the last bounding box in
/// track was detected more than specified number of
/// frames ago.
float affinity_thr; ///< Affinity threshold which is used to determine if
/// tracklet and detection should be combined.
float shape_affinity_w; ///< Shape affinity weight.
float motion_affinity_w; ///< Motion affinity weight.
float min_det_conf; ///< Min confidence of detection.
int averaging_window_size; ///< The number of objects in track for averaging predictions.
cv::Vec2f bbox_aspect_ratios_range; ///< Bounding box aspect ratios range.
cv::Vec2f bbox_heights_range; ///< Bounding box heights range.
bool drop_forgotten_tracks; ///< Drop forgotten tracks. If it's enabled it
/// disables an ability to get detection log.
int max_num_objects_in_track; ///< The number of objects in track is
/// restricted by this parameter. If it is negative or zero, the max number of
/// objects in track is not restricted.
std::string objects_type; ///< The type of boxes which will be grabbed from
/// detector. Boxes with other types are ignored.
///
/// Default constructor.
///
TrackerParams();
};
///
/// \brief The Track struct describes tracks.
///
struct Track {
///
/// \brief Track constructor.
/// \param objs Detected objects sequence.
///
explicit Track(const TrackedObjects &objs) : objects(objs), lost(0), length(1) {
CV_Assert(!objs.empty());
first_object = objs[0];
}
///
/// \brief empty returns if track does not contain objects.
/// \return true if track does not contain objects.
///
bool empty() const {
return objects.empty();
}
///
/// \brief size returns number of detected objects in a track.
/// \return number of detected objects in a track.
///
size_t size() const {
return objects.size();
}
///
/// \brief operator [] return const reference to detected object with
/// specified index.
/// \param i Index of object.
/// \return const reference to detected object with specified index.
///
const TrackedObject &operator[](size_t i) const {
return objects[i];
}
///
/// \brief operator [] return non-const reference to detected object with
/// specified index.
/// \param i Index of object.
/// \return non-const reference to detected object with specified index.
///
TrackedObject &operator[](size_t i) {
return objects[i];
}
///
/// \brief back returns const reference to last object in track.
/// \return const reference to last object in track.
///
const TrackedObject &back() const {
CV_Assert(!empty());
return objects.back();
}
///
/// \brief back returns non-const reference to last object in track.
/// \return non-const reference to last object in track.
///
TrackedObject &back() {
CV_Assert(!empty());
return objects.back();
}
TrackedObjects objects; ///< Detected objects;
size_t lost; ///< How many frames ago track has been lost.
TrackedObject first_object; ///< First object in track.
size_t length; ///< Length of a track including number of objects that were
/// removed from track in order to avoid memory usage growth.
};
///
/// \brief Simple Hungarian algorithm-based tracker.
///
class Tracker {
public:
///
/// \brief Constructor that creates an instance of Tracker with
/// parameters.
/// \param[in] params Tracker parameters.
///
explicit Tracker(const TrackerParams &params = TrackerParams())
: params_(params), tracks_counter_(0), valid_tracks_counter_(0), frame_size_() {
}
///
/// \brief Process given frame.
/// \param[in] frame Colored image (CV_8UC3).
/// \param[in] detections Detected objects on the frame.
/// \param[in] timestamp Timestamp must be positive and measured in
/// milliseconds
///
void Process(const cv::Size frame_size, const TrackedObjects &detections, int frame_idx);
///
/// \brief Pipeline parameters getter.
/// \return Parameters of pipeline.
///
const TrackerParams &params() const;
///
/// \brief Pipeline parameters setter.
/// \param[in] params Parameters of pipeline.
///
void set_params(const TrackerParams &params);
///
/// \brief Reset the pipeline.
///
void Reset();
///
/// \brief Returns number of counted tracks.
/// \return a number of counted tracks.
///
size_t Count() const;
///
/// \brief Returns recently detected objects.
/// \return recently detected objects.
///
const TrackedObjects &detections() const;
///
/// \brief Get active tracks to draw
/// \return Active tracks.
///
std::unordered_map<size_t, std::vector<cv::Point>> GetActiveTracks() const;
///
/// \brief Get tracked detections.
/// \return Tracked detections.
///
TrackedObjects TrackedDetections() const;
///
/// \brief Get tracked detections with labels.
/// \return Tracked detections.
///
TrackedObjects TrackedDetectionsWithLabels() const;
///
/// \brief IsTrackForgotten returns true if track is forgotten.
/// \param id Track ID.
/// \return true if track is forgotten.
///
bool IsTrackForgotten(size_t id) const;
///
/// \brief tracks Returns all tracks including forgotten (lost too many frames
/// ago).
/// \return Set of tracks {id, track}.
///
const std::unordered_map<size_t, Track> &tracks() const;
///
/// \brief tracks Returns all tracks including forgotten (lost too many frames
/// ago).
/// \return Vector of tracks
///
std::vector<Track> vector_tracks() const;
///
/// \brief IsTrackValid Checks whether track is valid (duration > threshold).
/// \param id Index of checked track.
/// \return True if track duration exceeds some predefined value.
///
bool IsTrackValid(size_t id) const;
///
/// \brief DropForgottenTracks Removes tracks from memory that were lost too
/// many frames ago.
///
void DropForgottenTracks();
private:
void DropForgottenTrack(size_t track_id);
const std::set<size_t> &active_track_ids() const {
return active_track_ids_;
}
float ShapeAffinity(const cv::Rect &trk, const cv::Rect &det);
float MotionAffinity(const cv::Rect &trk, const cv::Rect &det);
void SolveAssignmentProblem(const std::set<size_t> &track_ids, const TrackedObjects &detections,
std::set<size_t> *unmatched_tracks, std::set<size_t> *unmatched_detections,
std::set<std::tuple<size_t, size_t, float>> *matches);
void FilterDetectionsAndStore(const TrackedObjects &detected_objects);
void ComputeDissimilarityMatrix(const std::set<size_t> &active_track_ids, const TrackedObjects &detections,
cv::Mat *dissimilarity_matrix);
std::vector<std::pair<size_t, size_t>>
GetTrackToDetectionIds(const std::set<std::tuple<size_t, size_t, float>> &matches);
float Distance(const TrackedObject &obj1, const TrackedObject &obj2);
void AddNewTrack(const TrackedObject &detection);
void AddNewTracks(const TrackedObjects &detections);
void AddNewTracks(const TrackedObjects &detections, const std::set<size_t> &ids);
void AppendToTrack(size_t track_id, const TrackedObject &detection);
bool EraseTrackIfBBoxIsOutOfFrame(size_t track_id);
bool EraseTrackIfItWasLostTooManyFramesAgo(size_t track_id);
bool UptateLostTrackAndEraseIfItsNeeded(size_t track_id);
void UpdateLostTracks(const std::set<size_t> &track_ids);
std::unordered_map<size_t, std::vector<cv::Point>> GetActiveTracks();
// Parameters of the pipeline.
TrackerParams params_;
// Indexes of active tracks.
std::set<size_t> active_track_ids_;
// All tracks.
std::unordered_map<size_t, Track> tracks_;
// Recent detections.
TrackedObjects detections_;
// Number of all current tracks.
size_t tracks_counter_;
// Number of dropped valid tracks.
size_t valid_tracks_counter_;
cv::Size frame_size_;
};
int LabelWithMaxFrequencyInTrack(const Track &track);
std::vector<Track> UpdateTrackLabelsToBestAndFilterOutUnknowns(const std::vector<Track> &tracks);
此差异已折叠。
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef _GST_GVA_INFERENCE_H_
#define _GST_GVA_INFERENCE_H_
#include <gst/base/gstbasetransform.h>
#include "inference.h"
G_BEGIN_DECLS
#define GST_TYPE_GVA_INFERENCE (gst_gva_inference_get_type())
#define GST_GVA_INFERENCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GVA_INFERENCE, GstGvaInference))
#define GST_GVA_INFERENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_GVA_INFERENCE, GstGvaInferenceClass))
#define GST_IS_GVA_INFERENCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GVA_INFERENCE))
#define GST_IS_GVA_INFERENCE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_GVA_INFERENCE))
typedef struct _GstGvaInference GstGvaInference;
typedef struct _GstGvaInferenceClass GstGvaInferenceClass;
struct _GstGvaInference {
GstBaseTransform base_gvainference;
gchar *model;
gchar *device;
gchar *model_proc;
guint batch_size;
gfloat threshold;
gboolean resize_by_inference;
guint every_nth_frame;
guint nireq;
gchar *cpu_extension;
gchar *gpu_extension;
gchar *inference_id;
gchar *infer_config;
gboolean initialized;
gchar *cpu_streams;
GstVideoInfo *info;
InferenceProxy *inference;
};
struct _GstGvaInferenceClass {
GstBaseTransformClass base_gvainference_class;
};
GType gst_gva_inference_get_type(void);
G_END_DECLS
#endif
此差异已折叠。
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef __INFERENCE_H__
#define __INFERENCE_H__
#include <gst/video/video.h>
struct _GstGvaInference;
typedef struct _GstGvaInference GstGvaInference;
typedef struct _InferenceProxy InferenceProxy;
#ifdef __cplusplus
#include "blob2metadata.h"
#include "gva_tensor_meta.h"
#include "inference_backend/image_inference.h"
#include <list>
#include <mutex>
struct InferenceRefs {
unsigned int numRefs = 0;
std::list<GstGvaInference *> elementsToInit;
GstGvaInference *masterElement = nullptr;
InferenceProxy *proxy = nullptr;
};
class Inference {
private:
struct OutputFrame {
GstBuffer *buffer;
GstBaseTransform *filter;
};
struct InferenceResult : public InferenceBackend::ImageInference::IFrameBase {
InferenceFrame inference_frame;
std::pair<int, int> inference_frame_size;
std::list<OutputFrame> output_frames;
};
public:
Inference(GstGvaInference *ovino);
static InferenceProxy *aquire_instance(GstGvaInference *ovino);
static void release_instance(GstGvaInference *ovino);
void WorkingFunction(GstGvaInference *ovino);
GstFlowReturn TransformFrameIp(GstGvaInference *ovino, GstBaseTransform *trans, GstBuffer *buffer,
GstVideoInfo *info);
void SinkEvent(GstEvent *event);
void FlushInference();
~Inference();
private:
static void fillElementProps(GstGvaInference *targetElem, GstGvaInference *masterElem);
static void initExistingElements(InferenceRefs *infRefs);
void InferenceCompletionCallback(std::map<std::string, InferenceBackend::OutputBlob::Ptr> blobs,
std::vector<std::shared_ptr<InferenceBackend::ImageInference::IFrameBase>> frames);
mutable std::mutex _mutex;
int frame_num;
std::shared_ptr<InferenceBackend::ImageInference> image_inference;
std::shared_ptr<InferenceResult> result;
static std::map<std::string, InferenceRefs *> inference_pool_;
static std::mutex inference_pool_mutex_;
GstStructure *post_proc;
GstGvaInference *ovino_;
};
#else /* __cplusplus */
typedef struct Inference Inference;
#endif /* __cplusplus */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct _InferenceProxy {
Inference *instance;
};
InferenceProxy *aquire_inference(GstGvaInference *ovino, GError **error);
void release_inference(GstGvaInference *ovino);
void inference_sink_event(GstGvaInference *ovino, GstEvent *event);
GstFlowReturn frame_to_inference(GstGvaInference *ovino, GstBaseTransform *trans, GstBuffer *buf, GstVideoInfo *info);
void flush_inference(GstGvaInference *ovino);
#ifdef __cplusplus
} /* extern C */
#endif /* __cplusplus */
#endif /* __INFERENCE_H__ */
此差异已折叠。
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef __CONVERTERS_H__
#define __CONVERTERS_H__
#include "gstgvametaconvert.h"
#include "jsonconverter.h"
#include <gst/gst.h>
#include <string.h>
typedef struct {
const gchar *name;
convert_function_type function;
} ConverterMap;
extern ConverterMap converters[];
#endif /* __CONVERTERS_H__ */
此差异已折叠。
/*******************************************************************************
* Copyright (C) <2018-2019> Intel Corporation
*
* SPDX-License-Identifier: MIT
******************************************************************************/
#ifndef _GST_GVA_META_CONVERT_H_
#define _GST_GVA_META_CONVERT_H_
#include <gst/base/gstbasetransform.h>
#include <gst/video/video.h>
G_BEGIN_DECLS
#define GST_TYPE_GVA_META_CONVERT (gst_gva_meta_convert_get_type())
#define GST_GVA_META_CONVERT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GVA_META_CONVERT, GstGvaMetaConvert))
#define GST_GVA_META_CONVERT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_GVA_META_CONVERT, GstGvaMetaConvertClass))
#define GST_IS_GVA_META_CONVERT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GVA_META_CONVERT))
#define GST_IS_GVA_META_CONVERT_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_GVA_META_CONVERT))
typedef struct _GstGvaMetaConvert GstGvaMetaConvert;
typedef struct _GstGvaMetaConvertClass GstGvaMetaConvertClass;
typedef void (*convert_function_type)(GstGvaMetaConvert *converter, GstBuffer *buffer);
struct _GstGvaMetaConvert {
GstBaseTransform base_gvametaconvert;
gchar *model;
gchar *converter;
gchar *method;
gchar *source;
gchar *tags;
gchar *attribute_name;
gboolean include_no_detections;
gchar *layer_name;
gchar *inference_id;
gfloat threshold;
gboolean signal_handoffs;
convert_function_type convert_function;
gchar *location;
GstVideoInfo *info;
};
struct _GstGvaMetaConvertClass {
GstBaseTransformClass base_gvametaconvert_class;
void (*handoff)(GstElement *element, GstBuffer *buf);
};
GType gst_gva_meta_convert_get_type(void);
G_END_DECLS
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册