Fixed issue of low quality stream in JPEG: new default to RGB RAW RTP stream

Backward compatibility through menu un stream output view (allow selecting JPEG)
This commit is contained in:
Bruno Herbelin
2021-12-29 14:37:56 +01:00
parent ff48877d16
commit 76a2535da3
7 changed files with 73 additions and 40 deletions

View File

@@ -261,22 +261,34 @@ void NetworkStream::update()
// general case : create pipeline and open // general case : create pipeline and open
if (!failed_) { if (!failed_) {
// build the pipeline depending on stream info // build the pipeline depending on stream info
std::ostringstream pipeline;
// get generic pipeline string
std::string pipelinestring = NetworkToolkit::protocol_receive_pipeline[config_.protocol]; std::string pipelinestring = NetworkToolkit::protocol_receive_pipeline[config_.protocol];
// find placeholder for PORT
int xxxx = pipelinestring.find("XXXX");
// keep beginning of pipeline
pipeline << pipelinestring.substr(0, xxxx);
// Replace 'XXXX' by info on port config
pipeline << parameter;
// keep ending of pipeline
pipeline << pipelinestring.substr(xxxx + 4);
// add a videoconverter
pipeline << " ! videoconvert";
// find placeholder for PORT or SHH socket
size_t xxxx = pipelinestring.find("XXXX");
if (xxxx != std::string::npos)
// Replace 'XXXX' by info on port config
pipelinestring.replace(xxxx, 4, parameter);
// find placeholder for WIDTH
size_t wwww = pipelinestring.find("WWWW");
if (wwww != std::string::npos)
// Replace 'WWWW' by width
pipelinestring.replace(wwww, 4, std::to_string(config_.width) );
// find placeholder for HEIGHT
size_t hhhh = pipelinestring.find("HHHH");
if (hhhh != std::string::npos)
// Replace 'WWWW' by height
pipelinestring.replace(hhhh, 4, std::to_string(config_.height) );
// add a videoconverter
pipelinestring.append(" ! videoconvert ");
#ifdef NETWORK_DEBUG
Log::Info("Openning pipeline %s", pipelinestring.c_str());
#endif
// open the pipeline with generic stream class // open the pipeline with generic stream class
Stream::open(pipeline.str(), config_.width, config_.height); Stream::open(pipelinestring, config_.width, config_.height);
} }
} }
else { else {

View File

@@ -78,32 +78,42 @@
* RCV * RCV
* gst-launch-1.0 shmsrc is-live=true socket-path=/tmp/blah ! video/x-raw, format=RGB, framerate=30/1, width=320, height=240 ! videoconvert ! autovideosink * gst-launch-1.0 shmsrc is-live=true socket-path=/tmp/blah ! video/x-raw, format=RGB, framerate=30/1, width=320, height=240 ! videoconvert ! autovideosink
* *
* RTP UDP JPEG
*
* SND
* gst-launch-1.0 videotestsrc is-live=true ! video/x-raw, format=RGB, framerate=30/1 ! videoconvert ! video/x-raw, format=I420 ! jpegenc quality=95 ! rtpjpegpay ! udpsink port=5000 host=127.0.0
* RCV
* gst-launch-1.0 udpsrc buffer-size=200000 port=5000 ! application/x-rtp,encoding-name=JPEG ! rtpjpegdepay ! queue max-size-buffers=10 ! jpegdec ! videoconvert ! video/x-raw, format=RGB ! autovideosink
*
* */ * */
const char* NetworkToolkit::protocol_name[NetworkToolkit::DEFAULT] = { const char* NetworkToolkit::protocol_name[NetworkToolkit::DEFAULT] = {
"Shared Memory", "RGB Stream",
"RTP JPEG Stream", "JPEG Stream",
"RTP H264 Stream", "H264 Stream",
"RTP JPEG Broadcast", "JPEG Broadcast",
"RTP H264 Broadcast" "H264 Broadcast",
"RGB Shared Memory"
}; };
const std::vector<std::string> NetworkToolkit::protocol_send_pipeline { const std::vector<std::string> NetworkToolkit::protocol_send_pipeline {
"video/x-raw, format=RGB, framerate=30/1 ! queue max-size-buffers=10 ! shmsink buffer-time=100000 wait-for-connection=true name=sink", "video/x-raw, format=RGB, framerate=30/1 ! queue max-size-buffers=3 ! rtpvrawpay ! application/x-rtp,sampling=RGB ! udpsink name=sink",
"video/x-raw, format=I420, framerate=30/1 ! queue max-size-buffers=10 ! jpegenc idct-method=float ! rtpjpegpay ! udpsink name=sink", "video/x-raw, format=I420, framerate=30/1 ! queue max-size-buffers=10 ! jpegenc quality=95 ! rtpjpegpay ! udpsink name=sink",
"video/x-raw, format=I420, framerate=30/1 ! queue max-size-buffers=10 ! x264enc tune=\"zerolatency\" threads=2 ! rtph264pay ! udpsink name=sink", "video/x-raw, format=I420, framerate=30/1 ! queue max-size-buffers=10 ! x264enc tune=\"zerolatency\" threads=2 ! rtph264pay ! udpsink name=sink",
"video/x-raw, format=I420, framerate=30/1 ! queue max-size-buffers=3 ! jpegenc idct-method=float ! rtpjpegpay ! rtpstreampay ! tcpserversink name=sink", "video/x-raw, format=I420, framerate=30/1 ! queue max-size-buffers=3 ! jpegenc idct-method=float ! rtpjpegpay ! rtpstreampay ! tcpserversink name=sink",
"video/x-raw, format=I420, framerate=30/1 ! queue max-size-buffers=3 ! x264enc tune=\"zerolatency\" threads=2 ! rtph264pay ! rtpstreampay ! tcpserversink name=sink" "video/x-raw, format=I420, framerate=30/1 ! queue max-size-buffers=3 ! x264enc tune=\"zerolatency\" threads=2 ! rtph264pay ! rtpstreampay ! tcpserversink name=sink",
"video/x-raw, format=RGB, framerate=30/1 ! queue max-size-buffers=10 ! shmsink buffer-time=100000 wait-for-connection=true name=sink"
}; };
const std::vector<std::string> NetworkToolkit::protocol_receive_pipeline { const std::vector<std::string> NetworkToolkit::protocol_receive_pipeline {
"udpsrc buffer-size=200000 port=XXXX caps=\"application/x-rtp,media=(string)video,encoding-name=(string)RAW,sampling=(string)RGB,width=(string)WWWW,height=(string)HHHH\" ! rtpvrawdepay ! queue max-size-buffers=10",
"udpsrc buffer-size=200000 port=XXXX ! application/x-rtp,encoding-name=JPEG ! rtpjpegdepay ! queue max-size-buffers=10 ! jpegdec",
"udpsrc buffer-size=200000 port=XXXX ! application/x-rtp,encoding-name=H264 ! rtph264depay ! queue max-size-buffers=10 ! avdec_h264",
"tcpclientsrc timeout=1 port=XXXX ! queue max-size-buffers=30 ! application/x-rtp-stream,media=video,encoding-name=JPEG ! rtpstreamdepay ! rtpjpegdepay ! jpegdec",
"tcpclientsrc timeout=1 port=XXXX ! queue max-size-buffers=30 ! application/x-rtp-stream,media=video,encoding-name=H264 ! rtpstreamdepay ! rtph264depay ! avdec_h264",
"shmsrc socket-path=XXXX ! video/x-raw, format=RGB, framerate=30/1 ! queue max-size-buffers=10", "shmsrc socket-path=XXXX ! video/x-raw, format=RGB, framerate=30/1 ! queue max-size-buffers=10",
"udpsrc buffer-size=200000 port=XXXX ! application/x-rtp,encoding-name=JPEG,payload=26,clock-rate=90000 ! queue max-size-buffers=10 ! rtpjpegdepay ! jpegdec",
"udpsrc buffer-size=200000 port=XXXX ! application/x-rtp,encoding-name=H264,payload=96,clock-rate=90000 ! queue ! rtph264depay ! avdec_h264",
"tcpclientsrc timeout=1 port=XXXX ! queue max-size-buffers=30 ! application/x-rtp-stream,media=video,encoding-name=JPEG,payload=26,clock-rate=90000 ! rtpstreamdepay ! rtpjpegdepay ! jpegdec",
"tcpclientsrc timeout=1 port=XXXX ! queue max-size-buffers=30 ! application/x-rtp-stream,media=video,encoding-name=H264,payload=96,clock-rate=90000 ! rtpstreamdepay ! rtph264depay ! avdec_h264"
}; };
bool initialized_ = false; bool initialized_ = false;

View File

@@ -23,11 +23,12 @@ namespace NetworkToolkit
{ {
typedef enum { typedef enum {
SHM_RAW = 0, UDP_RAW = 0,
UDP_JPEG, UDP_JPEG,
UDP_H264, UDP_H264,
TCP_JPEG, TCP_JPEG,
TCP_H264, TCP_H264,
SHM_RAW,
DEFAULT DEFAULT
} Protocol; } Protocol;

View File

@@ -110,6 +110,7 @@ void Settings::Save(uint64_t runtime)
applicationNode->SetAttribute("show_tooptips", application.show_tooptips); applicationNode->SetAttribute("show_tooptips", application.show_tooptips);
applicationNode->SetAttribute("accept_connections", application.accept_connections); applicationNode->SetAttribute("accept_connections", application.accept_connections);
applicationNode->SetAttribute("pannel_history_mode", application.pannel_current_session_mode); applicationNode->SetAttribute("pannel_history_mode", application.pannel_current_session_mode);
applicationNode->SetAttribute("stream_protocol", application.stream_protocol);
pRoot->InsertEndChild(applicationNode); pRoot->InsertEndChild(applicationNode);
// Widgets // Widgets
@@ -354,6 +355,7 @@ void Settings::Load()
applicationNode->QueryBoolAttribute("show_tooptips", &application.show_tooptips); applicationNode->QueryBoolAttribute("show_tooptips", &application.show_tooptips);
applicationNode->QueryBoolAttribute("accept_connections", &application.accept_connections); applicationNode->QueryBoolAttribute("accept_connections", &application.accept_connections);
applicationNode->QueryIntAttribute("pannel_history_mode", &application.pannel_current_session_mode); applicationNode->QueryIntAttribute("pannel_history_mode", &application.pannel_current_session_mode);
applicationNode->QueryIntAttribute("stream_protocol", &application.stream_protocol);
} }
// Widgets // Widgets

View File

@@ -242,6 +242,7 @@ struct Application
// settings exporters // settings exporters
RecordConfig record; RecordConfig record;
int stream_protocol;
// settings new source // settings new source
SourceConfig source; SourceConfig source;
@@ -279,6 +280,7 @@ struct Application
current_view = 1; current_view = 1;
current_workspace= 1; current_workspace= 1;
brush = glm::vec3(0.5f, 0.1f, 0.f); brush = glm::vec3(0.5f, 0.1f, 0.f);
stream_protocol = 0;
windows = std::vector<WindowConfig>(3); windows = std::vector<WindowConfig>(3);
windows[0].name = APP_TITLE; windows[0].name = APP_TITLE;
windows[0].w = 1600; windows[0].w = 1600;

View File

@@ -267,14 +267,15 @@ void Streaming::addStream(const std::string &sender, int reply_to, const std::st
conf.width = FrameGrabbing::manager().width(); conf.width = FrameGrabbing::manager().width();
conf.height = FrameGrabbing::manager().height(); conf.height = FrameGrabbing::manager().height();
// TEMP DISABLED : TODO Fix snap to allow system wide shared access // set protocol according to settings
conf.protocol = NetworkToolkit::UDP_RAW;
if (Settings::application.stream_protocol >= 0 && Settings::application.stream_protocol < NetworkToolkit::DEFAULT)
conf.protocol = (NetworkToolkit::Protocol) Settings::application.stream_protocol;
// offer SHM if same IP that our host IP (i.e. on the same machine) // TODO : ideal would be Shared Memory, but does not work with linux snap package...
// if( NetworkToolkit::is_host_ip(conf.client_address) ) // // offer SHM stream if same IP that our host IP (i.e. on the same machine)
// conf.protocol = NetworkToolkit::SHM_RAW; // if( conf.protocol == NetworkToolkit::UDP_RAW && NetworkToolkit::is_host_ip(conf.client_address) )
// // any other IP : offer network streaming // conf.protocol = NetworkToolkit::SHM_RAW;
// else
conf.protocol = NetworkToolkit::UDP_JPEG;
// build OSC message // build OSC message
char buffer[IP_MTU_SIZE]; char buffer[IP_MTU_SIZE];
@@ -330,7 +331,7 @@ std::string VideoStreamer::init(GstCaps *caps)
// prevent eroneous protocol values // prevent eroneous protocol values
if (config_.protocol < 0 || config_.protocol >= NetworkToolkit::DEFAULT) if (config_.protocol < 0 || config_.protocol >= NetworkToolkit::DEFAULT)
config_.protocol = NetworkToolkit::UDP_JPEG; config_.protocol = NetworkToolkit::UDP_RAW;
// create a gstreamer pipeline // create a gstreamer pipeline
std::string description = "appsrc name=src ! videoconvert ! "; std::string description = "appsrc name=src ! videoconvert ! ";
@@ -346,17 +347,17 @@ std::string VideoStreamer::init(GstCaps *caps)
} }
// setup streaming sink // setup streaming sink
if (config_.protocol == NetworkToolkit::UDP_JPEG || config_.protocol == NetworkToolkit::UDP_H264) { if (config_.protocol == NetworkToolkit::SHM_RAW) {
g_object_set (G_OBJECT (gst_bin_get_by_name (GST_BIN (pipeline_), "sink")),
"host", config_.client_address.c_str(),
"port", config_.port, NULL);
}
else if (config_.protocol == NetworkToolkit::SHM_RAW) {
std::string path = SystemToolkit::full_filename(SystemToolkit::temp_path(), "shm"); std::string path = SystemToolkit::full_filename(SystemToolkit::temp_path(), "shm");
path += std::to_string(config_.port); path += std::to_string(config_.port);
g_object_set (G_OBJECT (gst_bin_get_by_name (GST_BIN (pipeline_), "sink")), g_object_set (G_OBJECT (gst_bin_get_by_name (GST_BIN (pipeline_), "sink")),
"socket-path", path.c_str(), NULL); "socket-path", path.c_str(), NULL);
} }
else {
g_object_set (G_OBJECT (gst_bin_get_by_name (GST_BIN (pipeline_), "sink")),
"host", config_.client_address.c_str(),
"port", config_.port, NULL);
}
// setup custom app source // setup custom app source
src_ = GST_APP_SRC( gst_bin_get_by_name (GST_BIN (pipeline_), "src") ); src_ = GST_APP_SRC( gst_bin_get_by_name (GST_BIN (pipeline_), "src") );

View File

@@ -1449,10 +1449,15 @@ void UserInterface::RenderPreview()
ImGui::PopStyleColor(1); ImGui::PopStyleColor(1);
if (Settings::application.accept_connections) if (Settings::application.accept_connections)
{ {
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::Combo("Format", &Settings::application.stream_protocol, NetworkToolkit::protocol_name, 3);
static char dummy_str[512]; static char dummy_str[512];
sprintf(dummy_str, "%s", Connection::manager().info().name.c_str()); sprintf(dummy_str, "%s", Connection::manager().info().name.c_str());
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.9f));
ImGui::InputText("My ID", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly); ImGui::InputText("My ID", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleColor(1);
std::vector<std::string> ls = Streaming::manager().listStreams(); std::vector<std::string> ls = Streaming::manager().listStreams();
if (ls.size()>0) { if (ls.size()>0) {