mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2026-07-18 00:45:51 +00:00
VNC-330 Fix decoder recovery and improve video frame handling
This commit is contained in:
parent
1bb839897a
commit
d4af227b41
13 changed files with 36 additions and 24 deletions
|
|
@ -353,11 +353,11 @@ void EncodeManager::pruneLosslessRefresh(const Region& limits)
|
|||
}
|
||||
|
||||
void EncodeManager::writeUpdate(const UpdateInfo& ui, const ScreenSet &layout, const PixelBuffer* pb,
|
||||
const RenderedCursor* renderedCursor,
|
||||
const RenderedCursor* renderedCursor, bool fullRefreshRequested,
|
||||
size_t maxUpdateSize)
|
||||
{
|
||||
curMaxUpdateSize = maxUpdateSize;
|
||||
doUpdate(true, ui.changed, ui.copied, ui.copy_delta, ui.copypassed, layout, pb, renderedCursor);
|
||||
doUpdate(true, ui.changed, ui.copied, ui.copy_delta, ui.copypassed, layout, pb, renderedCursor, fullRefreshRequested);
|
||||
}
|
||||
|
||||
void EncodeManager::writeLosslessRefresh(const Region& req, const ScreenSet &layout, const PixelBuffer* pb,
|
||||
|
|
@ -376,7 +376,8 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
|
|||
const std::vector<CopyPassRect>& copypassed,
|
||||
const ScreenSet &layout,
|
||||
const PixelBuffer* pb,
|
||||
const RenderedCursor* renderedCursor) {
|
||||
const RenderedCursor* renderedCursor,
|
||||
bool fullRefreshRequested) {
|
||||
int nRects;
|
||||
Region changed, cursorRegion;
|
||||
struct timeval start;
|
||||
|
|
@ -442,7 +443,7 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
|
|||
|
||||
bool video_mode = video_mode_available && conn->cp.encoder_config.encoder != KasmVideoEncoders::Encoder::unavailable;
|
||||
if (video_mode) {
|
||||
video_mode = updateVideo(changed, layout, pb);
|
||||
video_mode = updateVideo(changed, layout, pb, fullRefreshRequested);
|
||||
if (!video_mode)
|
||||
conn->cp.encoder_config.encoder = KasmVideoEncoders::Encoder::unavailable;
|
||||
}
|
||||
|
|
@ -483,13 +484,11 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
|
|||
conn->writer()->writeFramebufferUpdateEnd();
|
||||
}
|
||||
|
||||
bool EncodeManager::updateVideo(const Region &changed, const ScreenSet &layout, const PixelBuffer *pb) {
|
||||
bool EncodeManager::updateVideo(const Region &changed, const ScreenSet &layout, const PixelBuffer *pb, bool fullRefreshRequested) {
|
||||
auto *screen_encoder_manager = dynamic_cast<ScreenEncoderManager<> *>(encoders[encoderKasmVideo]);
|
||||
if (!screen_encoder_manager)
|
||||
return false;
|
||||
|
||||
//const auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (screen_encoder_manager->get_encoder_config().encoder != conn->cp.encoder_config.encoder) {
|
||||
screen_encoder_manager->clear();
|
||||
screen_encoder_manager->set_params(conn->cp.encoder_config,
|
||||
|
|
@ -505,7 +504,7 @@ bool EncodeManager::updateVideo(const Region &changed, const ScreenSet &layout,
|
|||
return false;
|
||||
|
||||
static const Palette palette;
|
||||
if (!screen_encoder_manager->writeFrame(pb, palette))
|
||||
if (!screen_encoder_manager->writeFrame(pb, palette, fullRefreshRequested))
|
||||
return false;
|
||||
|
||||
std::vector<Rect> rects;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ namespace rfb {
|
|||
void pruneLosslessRefresh(const Region& limits);
|
||||
|
||||
void writeUpdate(const UpdateInfo& ui, const ScreenSet &layout, const PixelBuffer* pb,
|
||||
const RenderedCursor* renderedCursor,
|
||||
const RenderedCursor* renderedCursor, bool fullRefreshRequested,
|
||||
size_t maxUpdateSize = 2000);
|
||||
|
||||
void writeLosslessRefresh(const Region& req, const ScreenSet &layout, const PixelBuffer* pb,
|
||||
|
|
@ -105,9 +105,10 @@ namespace rfb {
|
|||
const std::vector<CopyPassRect> ©passed,
|
||||
const ScreenSet &layout,
|
||||
const PixelBuffer* pb,
|
||||
const RenderedCursor* renderedCursor);
|
||||
const RenderedCursor* renderedCursor,
|
||||
bool fullRefreshRequested = false);
|
||||
|
||||
bool updateVideo(const Region& changed, const ScreenSet &layout, const PixelBuffer* pb);
|
||||
bool updateVideo(const Region& changed, const ScreenSet &layout, const PixelBuffer* pb, bool fullRefreshRequested);
|
||||
|
||||
void prepareEncoders(bool allowLossy);
|
||||
|
||||
|
|
|
|||
|
|
@ -1038,6 +1038,8 @@ void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
|
|||
// Non-incremental update - treat as if area requested has changed
|
||||
updates.add_changed(reqRgn);
|
||||
|
||||
pendingClientRefresh = true;
|
||||
|
||||
// And send the screen layout to the client (which, unlike the
|
||||
// framebuffer dimensions, the client doesn't get during init)
|
||||
writer()->writeExtendedDesktopSize();
|
||||
|
|
@ -1571,7 +1573,10 @@ void VNCSConnectionST::writeDataUpdate()
|
|||
server->msToNextUpdate() / 1000;
|
||||
|
||||
if (!ui.is_empty()) {
|
||||
encodeManager.writeUpdate(ui, server->screenLayout, server->getPixelBuffer(), cursor, maxUpdateSize);
|
||||
encodeManager.writeUpdate(ui, server->screenLayout, server->getPixelBuffer(), cursor, pendingClientRefresh, maxUpdateSize);
|
||||
if (pendingClientRefresh)
|
||||
pendingClientRefresh = false;
|
||||
|
||||
copypassed.clear();
|
||||
gettimeofday(&lastRealUpdate, nullptr);
|
||||
losslessTimer.start(losslessThreshold);
|
||||
|
|
|
|||
|
|
@ -366,6 +366,7 @@ namespace rfb {
|
|||
char unixRelaySubscriptions[MAX_UNIX_RELAYS][MAX_UNIX_RELAY_NAME_LEN] = {};
|
||||
bool complainedAboutNoViewRights;
|
||||
std::string clientUsername;
|
||||
bool pendingClientRefresh{false};
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ namespace benchmarking {
|
|||
|
||||
manager.clearEncodingTime();
|
||||
if (!ui.is_empty()) {
|
||||
manager.writeUpdate(ui, layout, pb, nullptr);
|
||||
manager.writeUpdate(ui, layout, pb, nullptr, false);
|
||||
} else {
|
||||
rfb::Region region{pb->getRect()};
|
||||
manager.writeLosslessRefresh(region, layout, pb, nullptr, 2000);
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ namespace rfb {
|
|||
}
|
||||
|
||||
template<AVHWDeviceType HWDeviceType, AVPixelFormat AVPixFmt>
|
||||
bool FFMPEGHWEncoder<HWDeviceType, AVPixFmt>::render(const PixelBuffer *pb) {
|
||||
bool FFMPEGHWEncoder<HWDeviceType, AVPixFmt>::render(const PixelBuffer *pb, bool forceKeyFrame) {
|
||||
// compress
|
||||
int stride;
|
||||
const auto rect = layout.dimensions;
|
||||
|
|
@ -282,6 +282,9 @@ namespace rfb {
|
|||
frame->pict_type = AV_PICTURE_TYPE_NONE;
|
||||
}
|
||||
|
||||
if (forceKeyFrame)
|
||||
frame->pict_type = AV_PICTURE_TYPE_I;
|
||||
|
||||
const int src_stride_bytes = stride * bpp;
|
||||
|
||||
DEBUG_LOG(vlog, "render(): width=%d, height=%d, dst_width=%d, dst_height=%d, stride=%d pixels, stride_bytes=%d, bpp=%d",
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public:
|
|||
bool isSupported() const override;
|
||||
void writeRect(const PixelBuffer *pb, const Palette &palette) override;
|
||||
void writeSolidRect(int width, int height, const PixelFormat &pf, const rdr::U8 *colour) override;
|
||||
bool render(const PixelBuffer *pb) override;
|
||||
bool render(const PixelBuffer *pb, bool forceKeyFrame = false) override;
|
||||
void writeSkipRect() override;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ namespace rfb {
|
|||
}
|
||||
|
||||
template<uint8_t T>
|
||||
bool ScreenEncoderManager<T>::writeFrame(const PixelBuffer *pb, const Palette &palette) {
|
||||
bool ScreenEncoderManager<T>::writeFrame(const PixelBuffer *pb, const Palette &palette, bool forceKeyFrame) {
|
||||
if (screens_to_refresh.empty())
|
||||
return true;
|
||||
|
||||
|
|
@ -219,13 +219,13 @@ namespace rfb {
|
|||
if (screens_to_refresh.size() > 1) {
|
||||
tbb::task_group_context ctx;
|
||||
|
||||
tbb::parallel_for_each(screens_to_refresh.begin(), screens_to_refresh.end(), [this, pb, &ctx](uint8_t index) {
|
||||
tbb::parallel_for_each(screens_to_refresh.begin(), screens_to_refresh.end(), [this, pb, &ctx, forceKeyFrame](uint8_t index) {
|
||||
if (ctx.is_group_execution_cancelled())
|
||||
return;
|
||||
|
||||
auto &screen = screens[index];
|
||||
if (auto *encoder = screen.encoder; encoder) {
|
||||
screen.dirty = encoder->render(pb);
|
||||
screen.dirty = encoder->render(pb, forceKeyFrame);
|
||||
if (!screen.dirty)
|
||||
ctx.cancel_group_execution();
|
||||
}
|
||||
|
|
@ -242,7 +242,7 @@ namespace rfb {
|
|||
}
|
||||
} else {
|
||||
if (auto encoder = screens[head].encoder; encoder) {
|
||||
if (encoder->render(pb))
|
||||
if (encoder->render(pb, forceKeyFrame))
|
||||
send_frame(screens[head]);
|
||||
else
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ namespace rfb {
|
|||
// Encoder
|
||||
[[nodiscard]] bool isSupported() const override;
|
||||
|
||||
bool writeFrame(const PixelBuffer *pb, const Palette &palette);
|
||||
bool writeFrame(const PixelBuffer *pb, const Palette &palette, bool forceKeyFrame = false);
|
||||
void writeRect(const PixelBuffer *pb, const Palette &palette) override {}
|
||||
void writeSolidRect(int width, int height, const PixelFormat &pf, const rdr::U8 *colour) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ namespace rfb {
|
|||
return conn->cp.supportsEncoding(encodingKasmVideo);
|
||||
}
|
||||
|
||||
bool SoftwareEncoder::render(const PixelBuffer *pb) {
|
||||
bool SoftwareEncoder::render(const PixelBuffer *pb, bool forceKeyFrame) {
|
||||
// compress
|
||||
int stride;
|
||||
|
||||
|
|
@ -93,6 +93,9 @@ namespace rfb {
|
|||
frame->pict_type = AV_PICTURE_TYPE_NONE;
|
||||
}
|
||||
|
||||
if (forceKeyFrame)
|
||||
frame->pict_type = AV_PICTURE_TYPE_I;
|
||||
|
||||
const uint8_t *src_data[1] = {buffer};
|
||||
const int src_line_size[1] = {stride * bpp}; // RGB has bpp bytes per pixel
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ namespace rfb {
|
|||
bool isSupported() const override;
|
||||
void writeRect(const PixelBuffer *pb, const Palette &palette) override;
|
||||
void writeSolidRect(int width, int height, const PixelFormat &pf, const rdr::U8 *colour) override;
|
||||
bool render(const PixelBuffer *pb) override;
|
||||
bool render(const PixelBuffer *pb, bool forceKeyFrame = false) override;
|
||||
void writeSkipRect() override;
|
||||
};
|
||||
} // namespace rfb
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace rfb {
|
|||
public:
|
||||
VideoEncoder(Id id, SConnection *conn) :
|
||||
Encoder(id, conn, encodingKasmVideo, static_cast<EncoderFlags>(EncoderUseNativePF | EncoderLossy), -1) {}
|
||||
virtual bool render(const PixelBuffer *pb) = 0;
|
||||
virtual bool render(const PixelBuffer *pb, bool forceKeyFrame = false) = 0;
|
||||
virtual void writeSkipRect() = 0;
|
||||
~VideoEncoder() override = default;
|
||||
};
|
||||
|
|
|
|||
2
kasmweb
2
kasmweb
|
|
@ -1 +1 @@
|
|||
Subproject commit 005736944431d03699e09a17efe0d2eda7fa20da
|
||||
Subproject commit 9b4cf1d90b05779821dede55062841dda946bb87
|
||||
Loading…
Add table
Add a link
Reference in a new issue