refactored gstreamer pipeline

This commit is contained in:
Dzmitry Maladzenkau committed 2025-05-31 17:27:49 +02:00
1 parent 9d7c6a10c3
commit c812ce9ada
5 files changed
+173 -97

No files matched your search

+85 -37
View File
@@ -9,56 +9,104 @@ using std::placeholders::_1;
Image2rtsp::Image2rtsp() : Node("image2rtsp"){
// Declare and get the parameters
this->declare_parameter("source", "v4l2src device=/dev/video0");
this->declare_parameter("topic", "/color/image_raw");
this->declare_parameter("mountpoint", "/back");
this->declare_parameter("bitrate", "500");
this->declare_parameter("framerate", "30");
this->declare_parameter("caps_1", "video/x-raw, framerate =");
this->declare_parameter("caps_2", "/1,width=640,height=480");
this->declare_parameter("port", "8554");
this->declare_parameter("local_only", true);
this->declare_parameter("camera", false);
this->declare_parameter("compressed", false);
this->declare_parameter("topic", "/color/image_raw");
this->declare_parameter("mountpoint", "/back");
this->declare_parameter("port", "8554");
this->declare_parameter("local_only", true);
this->declare_parameter("camera", false);
this->declare_parameter("compressed", false);
source = this->get_parameter("source").as_string();
topic = this->get_parameter("topic").as_string();
mountpoint = this->get_parameter("mountpoint").as_string();
bitrate = this->get_parameter("bitrate").as_string();
framerate = this->get_parameter("framerate").as_string();
caps_1 = this->get_parameter("caps_1").as_string();
caps_2 = this->get_parameter("caps_2").as_string();
port = this->get_parameter("port").as_string();
local_only = this->get_parameter("local_only").as_bool();
camera = this->get_parameter("camera").as_bool();
compressed = this->get_parameter("compressed").as_bool();
this->declare_parameter("default_pipeline", R"(
( appsrc name=imagesrc do-timestamp=true min-latency=0 max-latency=0 max-bytes=1000 is-live=true !
videoconvert !
videoscale !
video/x-raw, framerate=30/1, width=640, height=480 !
x264enc tune=zerolatency bitrate=500 key-int-max=30 !
video/x-h264, profile=baseline !
rtph264pay name=pay0 pt=96 )
)");
this->declare_parameter("camera_pipeline", R"(
( v4l2src device=/dev/video0 !
videoconvert !
videoscale !
video/x-raw, framerate=30/1, width=640, height=480 !
x264enc tune=zerolatency bitrate=500 key-int-max=30 !
video/x-h264, profile=baseline !
rtph264pay name=pay0 pt=96 )
)");
topic = this->get_parameter("topic").as_string();
mountpoint = this->get_parameter("mountpoint").as_string();
port = this->get_parameter("port").as_string();
local_only = this->get_parameter("local_only").as_bool();
camera = this->get_parameter("camera").as_bool();
compressed = this->get_parameter("compressed").as_bool();
default_pipeline = this->get_parameter("default_pipeline").as_string();
camera_pipeline = this->get_parameter("camera_pipeline").as_string();
// Start the subscription
if (compressed == false){
subscription_ = this->create_subscription<sensor_msgs::msg::Image>(topic, 10, std::bind(&Image2rtsp::topic_callback, this, _1));
if (camera == false){
if (compressed == false){
subscription_ = this->create_subscription<sensor_msgs::msg::Image>(topic, 10, std::bind(&Image2rtsp::topic_callback, this, _1));
RCLCPP_INFO(this->get_logger(), "Subscribing to sensor_msgs::msg::Image");
}
else {
subscription_compressed_ = this->create_subscription<sensor_msgs::msg::CompressedImage>(topic, 10, std::bind(&Image2rtsp::compressed_topic_callback, this, _1));
RCLCPP_INFO(this->get_logger(), "Subscribing to sensor_msgs::msg::CompressedImage");
}
}
else{
subscription_compressed_ = this->create_subscription<sensor_msgs::msg::CompressedImage>(topic, 10, std::bind(&Image2rtsp::compressed_topic_callback, this, _1));
else {
RCLCPP_INFO(this->get_logger(), "Trying to access camera device");
}
// Start the RTSP server
video_mainloop_start();
rtsp_server = rtsp_server_create(port, local_only);
appsrc = NULL;
// Setup the pipeline
pipeline_tail = "key-int-max=30 ! video/x-h264, profile=baseline ! rtph264pay name=pay0 pt=96 )";
if (camera == false){
pipeline_head = "( appsrc name=imagesrc do-timestamp=true min-latency=0 max-latency=0 max-bytes=1000 is-live=true ! videoconvert ! videoscale ! ";
pipeline = pipeline_head + caps_1 + framerate + caps_2 + " ! x264enc tune=zerolatency bitrate=" + bitrate + pipeline_tail;
rtsp_server_add_url(mountpoint.c_str(), pipeline.c_str(), (GstElement **)&(appsrc));
}
else {
pipeline = "( " + source + " ! videoconvert ! videoscale ! " + caps_1 + framerate + caps_2 + " ! x264enc tune=zerolatency bitrate=" + bitrate + pipeline_tail;
rtsp_server_add_url(mountpoint.c_str(), pipeline.c_str(), NULL);
}
pipeline = camera ? camera_pipeline : default_pipeline;
framerate = extract_framerate(pipeline, 30);
rtsp_server_add_url(mountpoint.c_str(), pipeline.c_str(), camera ? nullptr : (GstElement **)&appsrc);
RCLCPP_INFO(this->get_logger(), "Stream available at rtsp://%s:%s%s", gst_rtsp_server_get_address(rtsp_server), port.c_str(), mountpoint.c_str());
}
uint Image2rtsp::extract_framerate(const std::string& pipeline, uint default_framerate = 30) {
std::string search_str = "framerate=";
size_t pos = pipeline.find(search_str);
if (pos == std::string::npos) {
RCLCPP_WARN(this->get_logger(), "Framerate not found in pipeline, using default: %d", default_framerate);
return default_framerate;
}
pos += search_str.length();
size_t end_pos = pipeline.find_first_of("/,", pos);
if (end_pos == std::string::npos) {
RCLCPP_WARN(this->get_logger(), "Invalid framerate format in pipeline, using default: %d", default_framerate);
return default_framerate;
}
std::string framerate_str = pipeline.substr(pos, end_pos - pos);
framerate_str.erase(0, framerate_str.find_first_not_of(" \t"));
framerate_str.erase(framerate_str.find_last_not_of(" \t") + 1);
try {
uint framerate = std::stoi(framerate_str);
if (framerate <= 0) {
RCLCPP_WARN(this->get_logger(), "Invalid framerate value %d, using default: %d", framerate, default_framerate);
return default_framerate;
}
RCLCPP_INFO(this->get_logger(), "Using set framerate %d", framerate);
return framerate;
} catch (const std::exception& e) {
RCLCPP_WARN(this->get_logger(), "Failed to parse framerate '%s', using default: %d", framerate_str.c_str(), default_framerate);
return default_framerate;
}
}
int main(int argc, char *argv[]){
rclcpp::init(argc, argv);
auto node = std::make_shared<Image2rtsp>();
+5 -5
View File
@@ -132,7 +132,7 @@ GstCaps *Image2rtsp::gst_caps_new_from_image(const sensor_msgs::msg::Image::Shar
"format", G_TYPE_STRING, format->second.c_str(),
"width", G_TYPE_INT, msg->width,
"height", G_TYPE_INT, msg->height,
"framerate", GST_TYPE_FRACTION, stoi(framerate), 1,
"framerate", GST_TYPE_FRACTION, framerate, 1,
nullptr);
}
@@ -181,9 +181,9 @@ void Image2rtsp::compressed_topic_callback(const sensor_msgs::msg::CompressedIma
// Determine the GStreamer caps
std::string gst_format;
switch (img.type()) {
case CV_8UC3: gst_format = "RGB"; break; // RGB images
case CV_8UC4: gst_format = "RGBA"; break; // RGBA images
case CV_8UC1: gst_format = "GRAY8"; break; // Grayscale images
case CV_8UC3: gst_format = "BGR"; break; // BGR images
case CV_8UC4: gst_format = "RGBA"; break; // RGBA images
case CV_8UC1: gst_format = "GRAY8"; break; // Grayscale images
default:
RCLCPP_ERROR(this->get_logger(), "Unsupported image type");
return;
@@ -193,7 +193,7 @@ void Image2rtsp::compressed_topic_callback(const sensor_msgs::msg::CompressedIma
"format", G_TYPE_STRING, gst_format.c_str(),
"width", G_TYPE_INT, img.cols,
"height", G_TYPE_INT, img.rows,
"framerate", GST_TYPE_FRACTION, stoi(framerate), 1,
"framerate", GST_TYPE_FRACTION, framerate, 1,
nullptr);
// Set caps on appsrc