Files

88 lines
2.4 KiB
Go

//go:build windows && cgo && !no_amf
package capture
import (
"fmt"
"overlord-client/cmd/agent/capture/amfbridge"
"sync/atomic"
"unsafe"
)
type amfD3D11TextureBackend struct {
encoder *amfbridge.Encoder
device unsafe.Pointer
inputWidth int
inputHeight int
encodeWidth int
encodeHeight int
fps int
dxgiFormat uint32
output []byte
forceIDR atomic.Bool
}
func newAMFD3D11TextureBackend() h264D3D11TextureBackend {
return &amfD3D11TextureBackend{output: make([]byte, 1024*1024)}
}
func (b *amfD3D11TextureBackend) Name() string { return "AMD AMF" }
func (b *amfD3D11TextureBackend) matches(req h264D3D11TextureRequest) bool {
return b.encoder != nil && b.device == req.Device && b.inputWidth == req.InputWidth &&
b.inputHeight == req.InputHeight && b.encodeWidth == req.EncodeWidth &&
b.encodeHeight == req.EncodeHeight && b.fps == req.FPS && b.dxgiFormat == req.DXGIFormat
}
func (b *amfD3D11TextureBackend) Encode(req h264D3D11TextureRequest) ([]byte, error) {
if !b.matches(req) {
b.Reset()
encoder, err := amfbridge.Create(req.Device, req.InputWidth, req.InputHeight, req.EncodeWidth,
req.EncodeHeight, req.FPS, req.DXGIFormat, targetH264Bitrate(req.EncodeWidth, req.EncodeHeight, req.FPS))
if err != nil {
return nil, err
}
b.encoder = encoder
b.device, b.inputWidth, b.inputHeight = req.Device, req.InputWidth, req.InputHeight
b.encodeWidth, b.encodeHeight, b.fps, b.dxgiFormat = req.EncodeWidth, req.EncodeHeight, req.FPS, req.DXGIFormat
}
pendingIDR := b.forceIDR.Swap(false)
forceIDR := req.ForceIDR || pendingIDR
for attempts := 0; attempts < 2; attempts++ {
result, outputSize, err := b.encoder.Encode(req.Texture, forceIDR, b.output)
if err != nil {
return nil, err
}
if result == 2 {
if outputSize <= 0 || outputSize > 64*1024*1024 {
return nil, fmt.Errorf("AMF returned invalid output size %d", int(outputSize))
}
b.output = make([]byte, outputSize)
forceIDR = false
continue
}
if outputSize <= 0 {
return nil, nil
}
out := make([]byte, outputSize)
copy(out, b.output[:outputSize])
return out, nil
}
return nil, fmt.Errorf("AMF output buffer resize retry failed")
}
func (b *amfD3D11TextureBackend) RequestKeyframe() { b.forceIDR.Store(true) }
func (b *amfD3D11TextureBackend) Reset() {
if b.encoder != nil {
b.encoder.Close()
}
b.encoder = nil
b.device = nil
b.forceIDR.Store(false)
}
func probeAMFD3D11() (bool, string) {
return amfbridge.Probe()
}