optimizations + clean some code
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user