NVENC support
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
package capture
|
||||
|
||||
import (
|
||||
"image"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CaptureSmokeOptions struct {
|
||||
Display int `json:"display"`
|
||||
Frames int `json:"frames"`
|
||||
FPS int `json:"fps,omitempty"`
|
||||
MaxHeight int `json:"max_height,omitempty"`
|
||||
}
|
||||
|
||||
type CaptureSmokeResult struct {
|
||||
Backend string `json:"backend"`
|
||||
Format string `json:"format,omitempty"`
|
||||
Display int `json:"display"`
|
||||
Frames int `json:"frames"`
|
||||
Attempts int `json:"attempts,omitempty"`
|
||||
OK int `json:"ok"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
AvgMS float64 `json:"avg_ms"`
|
||||
AvgCapMS float64 `json:"avg_cap_ms,omitempty"`
|
||||
AvgEncMS float64 `json:"avg_enc_ms,omitempty"`
|
||||
FirstEncMS float64 `json:"first_enc_ms,omitempty"`
|
||||
SteadyEncMS float64 `json:"steady_enc_ms,omitempty"`
|
||||
MaxMS float64 `json:"max_ms"`
|
||||
AvgBytes float64 `json:"avg_bytes,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func RunCaptureSmoke(opts CaptureSmokeOptions) []CaptureSmokeResult {
|
||||
if opts.Frames <= 0 {
|
||||
opts.Frames = 30
|
||||
}
|
||||
if opts.Display < 0 {
|
||||
opts.Display = 0
|
||||
}
|
||||
if opts.FPS > 0 {
|
||||
SetH264TargetFPS(opts.FPS)
|
||||
}
|
||||
if opts.MaxHeight != 0 {
|
||||
SetMaxResolution(opts.MaxHeight)
|
||||
}
|
||||
return []CaptureSmokeResult{
|
||||
runCaptureH264DirectSmokeCase("dxgi-h264-direct", opts.Display, opts.Frames),
|
||||
runCaptureSmokeCase("dxgi-preferred", opts.Display, opts.Frames, func(display int) (*image.RGBA, error) {
|
||||
SetDesktopDuplication(true)
|
||||
return CaptureDisplayRGBA(display)
|
||||
}),
|
||||
runCaptureSmokeCase("bitblt", opts.Display, opts.Frames, func(display int) (*image.RGBA, error) {
|
||||
SetDesktopDuplication(false)
|
||||
return CaptureDisplayRGBABitBlt(display)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func runCaptureH264DirectSmokeCase(backend string, display, frames int) CaptureSmokeResult {
|
||||
result := CaptureSmokeResult{Backend: backend, Format: "h264", Display: display, Frames: frames}
|
||||
SetDesktopDuplication(true)
|
||||
ResetDesktopCapture()
|
||||
var total time.Duration
|
||||
var totalCap time.Duration
|
||||
var totalEnc time.Duration
|
||||
var firstEnc time.Duration
|
||||
var steadyEnc time.Duration
|
||||
var steadyCount int
|
||||
var max time.Duration
|
||||
var totalBytes int
|
||||
maxAttempts := frames * 10
|
||||
if maxAttempts < frames {
|
||||
maxAttempts = frames
|
||||
}
|
||||
for result.Attempts = 0; result.Attempts < maxAttempts && result.OK < frames; result.Attempts++ {
|
||||
start := time.Now()
|
||||
data, width, height, capDur, encDur, used, err := captureDisplayDXGIH264(display, result.OK == 0)
|
||||
dur := time.Since(start)
|
||||
total += dur
|
||||
if used {
|
||||
totalCap += capDur
|
||||
totalEnc += encDur
|
||||
}
|
||||
if dur > max {
|
||||
max = dur
|
||||
}
|
||||
if err != nil {
|
||||
if result.OK == 0 {
|
||||
result.Error = err.Error()
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !used {
|
||||
if result.OK == 0 && result.Error == "" {
|
||||
result.Error = "direct path not used"
|
||||
}
|
||||
continue
|
||||
}
|
||||
if len(data) == 0 {
|
||||
if result.OK == 0 {
|
||||
result.Error = "empty h264 output"
|
||||
}
|
||||
continue
|
||||
}
|
||||
result.OK++
|
||||
result.Width = width
|
||||
result.Height = height
|
||||
totalBytes += len(data)
|
||||
result.Error = ""
|
||||
if result.OK == 1 {
|
||||
firstEnc = encDur
|
||||
} else {
|
||||
steadyEnc += encDur
|
||||
steadyCount++
|
||||
}
|
||||
}
|
||||
if result.Attempts > 0 {
|
||||
result.AvgMS = float64(total.Microseconds()) / 1000 / float64(result.Attempts)
|
||||
result.MaxMS = float64(max.Microseconds()) / 1000
|
||||
}
|
||||
if result.OK > 0 {
|
||||
result.AvgBytes = float64(totalBytes) / float64(result.OK)
|
||||
result.AvgCapMS = float64(totalCap.Microseconds()) / 1000 / float64(result.OK)
|
||||
result.AvgEncMS = float64(totalEnc.Microseconds()) / 1000 / float64(result.OK)
|
||||
result.FirstEncMS = float64(firstEnc.Microseconds()) / 1000
|
||||
if steadyCount > 0 {
|
||||
result.SteadyEncMS = float64(steadyEnc.Microseconds()) / 1000 / float64(steadyCount)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func runCaptureSmokeCase(backend string, display, frames int, fn func(int) (*image.RGBA, error)) CaptureSmokeResult {
|
||||
result := CaptureSmokeResult{Backend: backend, Display: display, Frames: frames}
|
||||
ResetDesktopCapture()
|
||||
var total time.Duration
|
||||
var max time.Duration
|
||||
for i := 0; i < frames; i++ {
|
||||
start := time.Now()
|
||||
img, err := fn(display)
|
||||
dur := time.Since(start)
|
||||
total += dur
|
||||
if dur > max {
|
||||
max = dur
|
||||
}
|
||||
if err != nil {
|
||||
result.Error = err.Error()
|
||||
continue
|
||||
}
|
||||
if img == nil {
|
||||
result.Error = "nil image"
|
||||
continue
|
||||
}
|
||||
result.OK++
|
||||
result.Width = img.Bounds().Dx()
|
||||
result.Height = img.Bounds().Dy()
|
||||
PutRGBA(img)
|
||||
}
|
||||
if frames > 0 {
|
||||
result.AvgMS = float64(total.Microseconds()) / 1000 / float64(frames)
|
||||
result.MaxMS = float64(max.Microseconds()) / 1000
|
||||
}
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user