在经历过vnc ,rdp之后,他们的体验很差,不管给多少配置操作起来总是卡卡的感觉。于是就打算用webrtc+ docker+xfce4来实现一个桌面,这个博客记录一下爬坑的历程吧。
第一步 获取视频流
获取视频流我采用的gstreamer+applink的方式,在回调中拿到视频流
直接上命令吧
// 1080p 30fps 的视频流,关键帧设置为2-5秒, key-int-max范围为:60-150之间 分辨率必须匹配,不匹配则无法抓取屏幕
GstElement *pipeline = gst_parse_launch("ximagesrc use-damage=0 ! video/x-raw,framerate=30/1,width=1920,height=1080 "
"! videoconvert ! x264enc tune=zerolatency bitrate=10000 speed-preset=superfast key-int-max=60"
" bframes=0 ! rtph264pay config-interval=1 pt=96 ! appsink name=sink sync=false",
NULL);
第二步拿到视频流使用webrtc传输
在gstreamer回调中这样做:
static GstFlowReturn on_new_sample_from_sink(GstElement *sink, gpointer user_data)
{
GstSample *sample = nullptr;
g_signal_emit_by_name(sink, "pull-sample", &sample);
if (sample == nullptr) {
LOG_INFO("No sample received.\n");
return GST_FLOW_ERROR;
}
GstBuffer *buffer = gst_sample_get_buffer(sample);
if (buffer == nullptr) {
LOG_INFO("Failed to get buffer from sample.\n");
gst_sample_unref(sample);
return GST_FLOW_ERROR;
}
GstMapInfo map;
if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) {
LOG_INFO("Buffer mapping failed.\n");
gst_sample_unref(sample);
return GST_FLOW_ERROR;
}
try {
// LOG_INFO("Received a new video frame in thread: {} ", getppid());
// myrtc *rtcInstance = static_cast<myrtc *>(user_data);
// if (rtcInstance == nullptr) {
// throw std::runtime_error("Null rtcInstance pointer.");
// }
// Send video data
// rtcInstance->send(reinterpret_cast<char *>(map.data), map.size);
MyWebSocket::get().sendFrame(reinterpret_cast<char *>(map.data), map.size);
}
catch (const std::exception &e) {
LOG_INFO("Exception caught in on_new_sample_from_sink: %s\n", e.what());
gst_buffer_unmap(buffer, &map);
gst_sample_unref(sample);
return GST_FLOW_ERROR;
}
gst_buffer_unmap(buffer, &map);
gst_sample_unref(sample);
return GST_FLOW_OK;
}
前端的代码我就不贴了,这里我只获取视频流没有获取音频流,键盘和鼠标(远程鼠标)事件我是通过websocekt +x11所提供的接口来实现的 。
cpu大概占用一个核,内存的峰值在170M
1080p的视频流,在对接了键盘和鼠标之后,要比vnc 和rdp 丝滑很多,和本机相差无几,cpu和内存也在可接受的范围内。
也可以根据具体的情况来调整gstramer的参数,达到理想的效果。 比如更低的帧率更低的码率,更低的分辨率这样的cpu和内存占用会更低。这只是初步的demo,后边我会慢慢完善份代码,在稳定之后开源了。
不过由于webrtc是P2P通讯,所以信令服务器和TURN是有必要的,目前我只是单机测试,信令服务器和webrtc 服务都写在同一个程序中。 算是雏形吧,后续慢慢完善。
国内做云桌面和远程协议的人太少了,资料也很少,只能自己爬坑 爬坑再爬坑…