refactored gstreamer pipeline
This commit is contained in:
1 parent
9d7c6a10c3
commit
c812ce9ada
5 files changed
+173
-97
No files matched your search
+85
-37
@@ -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
@@ -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
|
||||
|
||||
Reference in new issue
Block a user