#include <iostream>
#include <string>
#include "pipeline.hpp"
#define CONFIG_FILE_PATH "/opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-test1/dstest1_pgie_config.yml"
#define PGIE_CLASS_ID_VEHICLE 0
#define PGIE_CLASS_ID_PERSON 2
//计数方法
using namespace deepstream;
class ObjectCounter : public BufferProbe::IBatchMetadataObserver
{
public:
ObjectCounter() {}
virtual ~ObjectCounter() {}
virtual probeReturn handleData(BufferProbe &probe, const BatchMetadata &data) {
data.iterate([](const FrameMetadata &frame_data)
{
auto vehicle_count = 0;
auto person_count = 0;
frame_data.iterate([&](const ObjectMetadata& object_data) {
auto class_id = object_data.classId();
if (class_id == PGIE_CLASS_ID_VEHICLE) {
vehicle_count++;
} else if (class_id == PGIE_CLASS_ID_PERSON ) {
person_count++;
}
});
std::cout << "Object Counter: " <<
" Pad Idx = " << frame_data.padIndex() <<
" Frame Number = " << frame_data.frameNum() <<
" Vehicle Count = " << vehicle_count <<
" Person Count = " << person_count << std::endl; });
return probeReturn::Probe_Ok;
}
};
int main(int argc, char *argv[]) {
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " <YAML config file>" << std::endl;
std::cout << "OR: " << argv[0] << " <H264 filename>" << std::endl;
return 0;
}
std::string sink = "nveglglessink";
#if defined(__aarch64__)
sink = "nv3dsink";
#endif
try {
std::string file = argv[1];
std::string suffix = "yaml";
if (std::equal(suffix.rbegin(), suffix.rend(), file.rbegin())) {
Pipeline pipeline("deepstream-test1", file);
pipeline.attach("infer", new BufferProbe("counter", new ObjectCounter)).start().wait();
} else {
Pipeline pipeline("deepstream-test1");
/*
*"filesrc": 元素的类型,这里是一个文件源(filesrc),用于读取文件。
*"src": 元素的名称,在管道中作为唯一标识符使用。
*"location": 要设置的属性名称,表示文件的路径。
*file: 对应属性的值,这里是从命令行参数传递进来的文件路径。
*/
pipeline.add("filesrc", "src", "location", file)
//"h264parse": 元素的类型,是一个 H.264 解析器(h264parse),用于解析 H.264 编码的视频流。
//"parser": 元素的名称,在管道中作为唯一标识符使用。
.add("h264parse", "parser")
//"nvv4l2decoder": 元素的类型,是一个 NVIDIA 硬件加速的视频解码器(nvv4l2decoder),用于解码 H.264 编码的视频流。
//"decoder": 元素的名称,在管道中作为唯一标识符使用。
.add("nvv4l2decoder", "decoder")
/*
*"nvstreammux": 元素的类型,是一个视频流复用器(nvstreammux),用于将多个视频流合并成一个批处理视频流。
*"mux": 元素的名称,在管道中作为唯一标识符使用
*"batch-size", 1: 设置批处理大小为 1,表示一次处理一个视频流
*"width", 1280: 设置视频帧的宽度为 1280 像素
*"height", 720: 设置视频帧的高度为 720 像素
*/
.add("nvstreammux", "mux", "batch-size", 1, "width", 1280, "height", 720)
/*
*"nvinfer": 元素的类型,是一个推理引擎(nvinfer),用于运行深度学习模型进行推理。
*"infer": 元素的名称,在管道中作为唯一标识符使用。
*"config-file-path", CONFIG_FILE_PATH: 设置推理引擎的配置文件路径,这里使用预定义的 CONFIG_FILE_PATH。
*"nvvideoconvert": 元素的类型,是一个视频转换器(nvvideoconvert),用于转换视频帧的格式和颜色空间。
*"converter": 元素的名称,在管道中作为唯一标识符使用。
*/
.add("nvinfer", "infer", "config-file-path", CONFIG_FILE_PATH)
.add("nvvideoconvert", "converter")
//"nvdsosd": 元素的类型,是一个显示元素(nvdsosd),用于在视频帧上绘制对象边界框、标签和其他元数据。
//"osd": 元素的名称,在管道中作为唯一标识符使用。
.add("nvdsosd", "osd")
//sink: 变量,之前根据平台定义为 "nveglglessink" 或 "nv3dsink"。
//"sink": 元素的名称,在管道中作为唯一标识符使用。
//表示向管道中添加了一个显示或渲染的输出元素,用于显示处理后的视频流
.add(sink, "sink")
//将文件源、解析器和解码器连接起来,使数据流从文件源经过解析器,再到解码器
.link("src", "parser", "decoder")
/*
*{"decoder", "mux"}: 指定连接的输入元素。
*{"", "sink_%u"}: 指定连接的输出元素,其中 sink_%u 用于动态连接复用器的多个输出
*这行代码将解码器连接到复用器,并设置复用器的输出格式
*/
.link({"decoder", "mux"}, {"", "sink_%u"})
//将复用器、推理引擎、视频转换器、显示元素和输出连接起来,形成数据处理的完整路径
.link("mux", "infer", "converter", "osd", "sink")
/*"infer": 元素名称,指代推理引擎(nvinfer)。
*new BufferProbe("counter", new ObjectCounter): 创建一个新的探针 BufferProbe,并附加 ObjectCounter 实例。
*这行代码在推理引擎上附加了一个探针,用于统计和处理推理结果中的对象数量。
*/
.attach("infer", new BufferProbe("counter", new ObjectCounter))
/*
*"infer": 元素名称,指代推理引擎(nvinfer)。
*"sample_video_probe": 探针名称。
*"my probe": 自定义探针标签。
*"src": 元素的源,即探针连接的位置。
*"font-size", 20: 其他自定义参数,这里是字体大小。
*这行代码在推理引擎上附加了一个自定义探针,用于在视频帧上显示相关信息。
*/
.attach("infer", "sample_video_probe", "my probe", "src", "font-size", 20)
//.start(): 调用管道的 start 方法,启动
//.wait(): 调用管道的 wait 方法,等待管道完成
.start()
.wait();
}
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
return -1;
}
return 0;
}