optimizations + clean some code

This commit is contained in:
KingKDot
2026-05-21 23:28:06 -05:00
parent 06b001e5a1
commit bd47b233d6
7 changed files with 189 additions and 120 deletions
+113 -54
View File
@@ -3,7 +3,6 @@ package capture
import (
"bytes"
"context"
"encoding/binary"
"errors"
"image"
"image/draw"
@@ -798,6 +797,28 @@ func buildFrameHVNC(img *image.RGBA, display int, quality int) (wire.Frame, time
type streamRegion struct{ x, y, w, h int }
type encodeBufs struct {
changedGrid []bool
visited []bool
}
var (
encodeBufsPool = sync.Pool{New: func() interface{} { return &encodeBufs{} }}
frameBufPool = sync.Pool{New: func() interface{} { return bytes.NewBuffer(make([]byte, 0, 512*1024)) }}
)
func writeUint16LE(buf *bytes.Buffer, v uint16) {
buf.WriteByte(byte(v))
buf.WriteByte(byte(v >> 8))
}
func writeUint32LE(buf *bytes.Buffer, v uint32) {
buf.WriteByte(byte(v))
buf.WriteByte(byte(v >> 8))
buf.WriteByte(byte(v >> 16))
buf.WriteByte(byte(v >> 24))
}
type roiHint struct {
rect image.Rectangle
weight int
@@ -812,7 +833,21 @@ func encodeBlocks(img *image.RGBA, prev *prevImage, quality int, codec string, d
blocksWide := (width + blockSize - 1) / blockSize
blocksHigh := (height + blockSize - 1) / blockSize
changedGrid := make([]bool, blocksWide*blocksHigh)
total := blocksWide * blocksHigh
eb := encodeBufsPool.Get().(*encodeBufs)
defer encodeBufsPool.Put(eb)
if cap(eb.changedGrid) < total {
eb.changedGrid = make([]bool, total)
eb.visited = make([]bool, total)
} else {
eb.changedGrid = eb.changedGrid[:total]
eb.visited = eb.visited[:total]
clear(eb.changedGrid)
clear(eb.visited)
}
changedGrid := eb.changedGrid
visited := eb.visited
changedCount := 0
passDetectStart := time.Now()
@@ -843,17 +878,11 @@ func encodeBlocks(img *image.RGBA, prev *prevImage, quality int, codec string, d
statDetectNs.Add(time.Since(passDetectStart).Nanoseconds())
if changedCount == 0 {
buf := bytes.Buffer{}
_ = binary.Write(&buf, binary.LittleEndian, uint16(width))
_ = binary.Write(&buf, binary.LittleEndian, uint16(height))
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
return 0, buf.Bytes(), 0, nil
return 0, []byte{byte(width), byte(width >> 8), byte(height), byte(height >> 8), 0, 0, 0, 0}, 0, nil
}
mergeStart := time.Now()
var regions []streamRegion
visited := make([]bool, len(changedGrid))
for by := 0; by < blocksHigh; by++ {
for bx := 0; bx < blocksWide; bx++ {
@@ -926,39 +955,50 @@ func encodeBlocks(img *image.RGBA, prev *prevImage, quality int, codec string, d
statMergeNs.Add(time.Since(mergeStart).Nanoseconds())
buf := bytes.Buffer{}
_ = binary.Write(&buf, binary.LittleEndian, uint16(width))
_ = binary.Write(&buf, binary.LittleEndian, uint16(height))
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(regions)))
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
buf := frameBufPool.Get().(*bytes.Buffer)
buf.Reset()
defer frameBufPool.Put(buf)
writeUint16LE(buf, uint16(width))
writeUint16LE(buf, uint16(height))
writeUint16LE(buf, uint16(len(regions)))
writeUint16LE(buf, 0)
totalEncDur := time.Duration(0)
for _, r := range regions {
t0 := time.Now()
var payload []byte
var err error
writeUint16LE(buf, uint16(r.x))
writeUint16LE(buf, uint16(r.y))
writeUint16LE(buf, uint16(r.w))
writeUint16LE(buf, uint16(r.h))
var encErr error
if codec == "raw" {
payload = encodeBlockRaw(img, r.x, r.y, r.w, r.h)
payload := encodeBlockRaw(img, r.x, r.y, r.w, r.h)
writeUint32LE(buf, uint32(len(payload)))
buf.Write(payload)
} else {
blockQuality := quality + 10
if blockQuality > 100 {
blockQuality = 100
}
payload, err = encodeJPEG(img.SubImage(image.Rect(r.x, r.y, r.x+r.w, r.y+r.h)), blockQuality)
lenPos := buf.Len()
writeUint32LE(buf, 0) // placeholder; patched below with actual JPEG size
encErr = encodeJPEGToBuf(buf, img.SubImage(image.Rect(r.x, r.y, r.x+r.w, r.y+r.h)), blockQuality)
if encErr == nil {
jpegLen := uint32(buf.Len() - lenPos - 4)
b := buf.Bytes()
b[lenPos] = byte(jpegLen)
b[lenPos+1] = byte(jpegLen >> 8)
b[lenPos+2] = byte(jpegLen >> 16)
b[lenPos+3] = byte(jpegLen >> 24)
}
}
blockDur := time.Since(t0)
totalEncDur += blockDur
statBlkJpegNs.Add(blockDur.Nanoseconds())
if err != nil {
return len(regions), nil, totalEncDur, err
if encErr != nil {
return len(regions), nil, totalEncDur, encErr
}
_ = binary.Write(&buf, binary.LittleEndian, uint16(r.x))
_ = binary.Write(&buf, binary.LittleEndian, uint16(r.y))
_ = binary.Write(&buf, binary.LittleEndian, uint16(r.w))
_ = binary.Write(&buf, binary.LittleEndian, uint16(r.h))
_ = binary.Write(&buf, binary.LittleEndian, uint32(len(payload)))
buf.Write(payload)
}
prevCopyStart := time.Now()
@@ -967,7 +1007,9 @@ func encodeBlocks(img *image.RGBA, prev *prevImage, quality int, codec string, d
prevMu.Unlock()
statPrevCopyNs.Add(time.Since(prevCopyStart).Nanoseconds())
return len(regions), buf.Bytes(), totalEncDur, nil
out := make([]byte, buf.Len())
copy(out, buf.Bytes())
return len(regions), out, totalEncDur, nil
}
func blockChanged(cur, prev []byte, curStride, prevStride int, x, y, w, h int) bool {
@@ -1152,7 +1194,21 @@ func encodeBlocksHVNC(img *image.RGBA, prev *prevImage, quality int, codec strin
blocksWide := (width + blockSize - 1) / blockSize
blocksHigh := (height + blockSize - 1) / blockSize
changedGrid := make([]bool, blocksWide*blocksHigh)
total := blocksWide * blocksHigh
eb := encodeBufsPool.Get().(*encodeBufs)
defer encodeBufsPool.Put(eb)
if cap(eb.changedGrid) < total {
eb.changedGrid = make([]bool, total)
eb.visited = make([]bool, total)
} else {
eb.changedGrid = eb.changedGrid[:total]
eb.visited = eb.visited[:total]
clear(eb.changedGrid)
clear(eb.visited)
}
changedGrid := eb.changedGrid
visited := eb.visited
changedCount := 0
passDetectStart := time.Now()
@@ -1179,17 +1235,11 @@ func encodeBlocksHVNC(img *image.RGBA, prev *prevImage, quality int, codec strin
statDetectNs.Add(time.Since(passDetectStart).Nanoseconds())
if changedCount == 0 {
buf := bytes.Buffer{}
_ = binary.Write(&buf, binary.LittleEndian, uint16(width))
_ = binary.Write(&buf, binary.LittleEndian, uint16(height))
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
return 0, buf.Bytes(), 0, nil
return 0, []byte{byte(width), byte(width >> 8), byte(height), byte(height >> 8), 0, 0, 0, 0}, 0, nil
}
mergeStart := time.Now()
var regions []streamRegion
visited := make([]bool, len(changedGrid))
for by := 0; by < blocksHigh; by++ {
for bx := 0; bx < blocksWide; bx++ {
@@ -1261,37 +1311,44 @@ func encodeBlocksHVNC(img *image.RGBA, prev *prevImage, quality int, codec strin
sortRegionsByROI(regions, rois)
statMergeNs.Add(time.Since(mergeStart).Nanoseconds())
buf := bytes.Buffer{}
_ = binary.Write(&buf, binary.LittleEndian, uint16(width))
_ = binary.Write(&buf, binary.LittleEndian, uint16(height))
_ = binary.Write(&buf, binary.LittleEndian, uint16(len(regions)))
_ = binary.Write(&buf, binary.LittleEndian, uint16(0))
buf := frameBufPool.Get().(*bytes.Buffer)
buf.Reset()
defer frameBufPool.Put(buf)
writeUint16LE(buf, uint16(width))
writeUint16LE(buf, uint16(height))
writeUint16LE(buf, uint16(len(regions)))
writeUint16LE(buf, 0)
totalEncDur := time.Duration(0)
for _, r := range regions {
encStart := time.Now()
var payload []byte
var err error
writeUint16LE(buf, uint16(r.x))
writeUint16LE(buf, uint16(r.y))
writeUint16LE(buf, uint16(r.w))
writeUint16LE(buf, uint16(r.h))
if codec == "raw" {
payload = encodeBlockRaw(img, r.x, r.y, r.w, r.h)
payload := encodeBlockRaw(img, r.x, r.y, r.w, r.h)
writeUint32LE(buf, uint32(len(payload)))
buf.Write(payload)
} else {
blockQuality := quality + 10
if blockQuality > 100 {
blockQuality = 100
}
payload, err = encodeJPEG(img.SubImage(image.Rect(r.x, r.y, r.x+r.w, r.y+r.h)), blockQuality)
if err != nil {
lenPos := buf.Len()
writeUint32LE(buf, 0) // placeholder; patched below with actual JPEG size
if err := encodeJPEGToBuf(buf, img.SubImage(image.Rect(r.x, r.y, r.x+r.w, r.y+r.h)), blockQuality); err != nil {
return 0, nil, 0, err
}
jpegLen := uint32(buf.Len() - lenPos - 4)
b := buf.Bytes()
b[lenPos] = byte(jpegLen)
b[lenPos+1] = byte(jpegLen >> 8)
b[lenPos+2] = byte(jpegLen >> 16)
b[lenPos+3] = byte(jpegLen >> 24)
}
totalEncDur += time.Since(encStart)
_ = binary.Write(&buf, binary.LittleEndian, uint16(r.x))
_ = binary.Write(&buf, binary.LittleEndian, uint16(r.y))
_ = binary.Write(&buf, binary.LittleEndian, uint16(r.w))
_ = binary.Write(&buf, binary.LittleEndian, uint16(r.h))
_ = binary.Write(&buf, binary.LittleEndian, uint32(len(payload)))
buf.Write(payload)
}
prevCopyStart := time.Now()
@@ -1300,7 +1357,9 @@ func encodeBlocksHVNC(img *image.RGBA, prev *prevImage, quality int, codec strin
prevMu.Unlock()
statPrevCopyNs.Add(time.Since(prevCopyStart).Nanoseconds())
return len(regions), buf.Bytes(), totalEncDur, nil
out := make([]byte, buf.Len())
copy(out, buf.Bytes())
return len(regions), out, totalEncDur, nil
}
func copyPrev(img *image.RGBA) {
@@ -27,3 +27,15 @@ func encodeJPEG(img image.Image, quality int) ([]byte, error) {
jpegBufPool.Put(buf)
return out, nil
}
func encodeJPEGToBuf(dst *bytes.Buffer, img image.Image, quality int) error {
buf := jpegBufPool.Get().(*bytes.Buffer)
buf.Reset()
if err := jpeg.Encode(buf, img, &jpeg.Options{Quality: quality}); err != nil {
jpegBufPool.Put(buf)
return err
}
dst.Write(buf.Bytes())
jpegBufPool.Put(buf)
return nil
}
@@ -21,3 +21,12 @@ func encodeJPEG(img image.Image, quality int) ([]byte, error) {
}
return buf.Bytes(), nil
}
func encodeJPEGToBuf(dst *bytes.Buffer, img image.Image, quality int) error {
opts := &ljpeg.EncoderOptions{
Quality: quality,
OptimizeCoding: true,
DCTMethod: ljpeg.DCTISlow,
}
return ljpeg.Encode(dst, img, opts)
}
@@ -13,8 +13,7 @@ func GetRGBA(w, h int) *image.RGBA {
return image.NewRGBA(image.Rect(0, 0, w, h))
}
if v := rgbaPool.Get(); v != nil {
buf := v.([]byte)
if cap(buf) >= need {
if buf, ok := v.([]byte); ok && cap(buf) >= need {
return &image.RGBA{
Pix: buf[:need],
Stride: w * 4,