mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-04 12:39:06 +02:00
Collapse dirty rects to their bounding box when the bbox is densely dirty
This commit is contained in:
@@ -32,6 +32,21 @@ const (
|
|||||||
fullFramePromoteDen = 100
|
fullFramePromoteDen = 100
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// bboxPromoteDensityPct collapses the coalesced rect list down to its
|
||||||
|
// bounding box when the dirty pixels occupy at least this fraction of the
|
||||||
|
// bbox. Catches the "windowed video" case where the player area dirties as
|
||||||
|
// a dense block but is split into many sibling rects by overlays or by
|
||||||
|
// non-uniform tile coverage. Sending one JPEG over the bbox beats sending
|
||||||
|
// dozens of small JPEGs that each carry their own header and Tight stream
|
||||||
|
// restart.
|
||||||
|
const (
|
||||||
|
bboxPromoteDensityPct = 70
|
||||||
|
// bboxPromoteMinArea avoids promoting a handful of small scattered
|
||||||
|
// rects whose bbox would span most of the screen and pull in mostly
|
||||||
|
// clean pixels.
|
||||||
|
bboxPromoteMinArea = tileSize * tileSize * 16
|
||||||
|
)
|
||||||
|
|
||||||
type session struct {
|
type session struct {
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
capturer ScreenCapturer
|
capturer ScreenCapturer
|
||||||
|
|||||||
@@ -120,6 +120,11 @@ func (s *session) processIncremental(img *image.RGBA) error {
|
|||||||
s.refreshCopyRectIndex()
|
s.refreshCopyRectIndex()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if len(moves) == 0 {
|
||||||
|
if bb, ok := promoteToBoundingBox(rects); ok {
|
||||||
|
rects = bb
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := s.sendDirtyAndMoves(img, moves, rects); err != nil {
|
if err := s.sendDirtyAndMoves(img, moves, rects); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -311,6 +316,45 @@ func (s *session) captureFrame() (*image.RGBA, error) {
|
|||||||
return s.curFrame, nil
|
return s.curFrame, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// promoteToBoundingBox replaces the rect list with a single rect covering
|
||||||
|
// the bounding box of all inputs, provided the bbox is at least
|
||||||
|
// bboxPromoteMinArea and the dirty pixels fill at least
|
||||||
|
// bboxPromoteDensityPct of it. Returns the new rect list and true when the
|
||||||
|
// promotion fires; otherwise returns nil, false and the caller keeps the
|
||||||
|
// original list.
|
||||||
|
func promoteToBoundingBox(rects [][4]int) ([][4]int, bool) {
|
||||||
|
if len(rects) < 2 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
x0, y0 := rects[0][0], rects[0][1]
|
||||||
|
x1, y1 := x0+rects[0][2], y0+rects[0][3]
|
||||||
|
dirty := 0
|
||||||
|
for _, r := range rects {
|
||||||
|
if r[0] < x0 {
|
||||||
|
x0 = r[0]
|
||||||
|
}
|
||||||
|
if r[1] < y0 {
|
||||||
|
y0 = r[1]
|
||||||
|
}
|
||||||
|
if r[0]+r[2] > x1 {
|
||||||
|
x1 = r[0] + r[2]
|
||||||
|
}
|
||||||
|
if r[1]+r[3] > y1 {
|
||||||
|
y1 = r[1] + r[3]
|
||||||
|
}
|
||||||
|
dirty += r[2] * r[3]
|
||||||
|
}
|
||||||
|
w, h := x1-x0, y1-y0
|
||||||
|
bbox := w * h
|
||||||
|
if bbox < bboxPromoteMinArea {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
if dirty*100 < bbox*bboxPromoteDensityPct {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return [][4]int{{x0, y0, w, h}}, true
|
||||||
|
}
|
||||||
|
|
||||||
// shouldPromoteToFullFrame returns true when the dirty rect set covers a
|
// shouldPromoteToFullFrame returns true when the dirty rect set covers a
|
||||||
// large enough fraction of the screen that a single full-frame zlib rect
|
// large enough fraction of the screen that a single full-frame zlib rect
|
||||||
// beats per-tile encoding on both CPU time and wire bytes. The crossover
|
// beats per-tile encoding on both CPU time and wire bytes. The crossover
|
||||||
|
|||||||
Reference in New Issue
Block a user