fix(videochannel): force VP8 keyframes and drop bad frames

This commit is contained in:
zarazaex69
2026-05-27 10:55:37 +03:00
parent 0a5d3fb922
commit 552151fece
4 changed files with 18 additions and 31 deletions

2
go.mod
View File

@@ -3,7 +3,7 @@ module github.com/openlibrecommunity/olcrtc
go 1.26.3
require (
codeberg.org/rape4me/kc v0.0.0-20260527043314-71657a097a6f
codeberg.org/rape4me/kc v0.0.0-20260527074346-4cb2a45790c2
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674
github.com/livekit/protocol v1.46.0

4
go.sum
View File

@@ -7,8 +7,8 @@ buf.build/go/protoyaml v0.7.0/go.mod h1:+a0cavd0uMvirb87xdu2ZMMmjlIQoiH/N2Ich5MG
cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs=
cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
codeberg.org/rape4me/kc v0.0.0-20260527043314-71657a097a6f h1:amyzfF9+4jCUKJndW336YHbj3FiaWs/qkJqOgUyreCA=
codeberg.org/rape4me/kc v0.0.0-20260527043314-71657a097a6f/go.mod h1:ooInikVAZhJE+m+gHIekq52ZFkUPcCZAvY4u/m2M/V0=
codeberg.org/rape4me/kc v0.0.0-20260527074346-4cb2a45790c2 h1:u7QorW08YOZGj86cubeGpiwm+d0tMKa0e7syiBkO2eo=
codeberg.org/rape4me/kc v0.0.0-20260527074346-4cb2a45790c2/go.mod h1:ooInikVAZhJE+m+gHIekq52ZFkUPcCZAvY4u/m2M/V0=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=

View File

@@ -20,8 +20,10 @@ type goEncoder struct {
}
func newGoEncoder(width, height, _ int) *goEncoder {
enc := vp8.NewEncoder(width, height, 63)
enc.SetKeyInterval(1)
return &goEncoder{
enc: vp8.NewEncoder(width, height, 10),
enc: enc,
width: width,
height: height,
frameSize: width * height,
@@ -74,12 +76,10 @@ func (d *goDecoder) PushSample(sample []byte) error {
}
frame, err := d.dec.Decode(sample)
if err != nil {
// Inter-frame arrived before any keyframe (e.g. SFU started forwarding
// mid-GOP). Drop silently; the next keyframe will reset the reference.
if errors.Is(err, vp8.ErrNoReference) {
return nil
return nil // skip inter-frames until keyframe arrives
}
return fmt.Errorf("vp8 decode: %w", err)
return nil // skip undecodable frames (e.g. from other participants)
}
gray := frame.Grayscale()
select {

View File

@@ -88,9 +88,6 @@ type streamTransport struct {
remoteRole byte
bindingToken uint32
runCtx context.Context //nolint:containedctx,lll // long-lived context drives idle-frame loops bound to this transport's lifetime
idleFrame []byte
idleFrameMu sync.Mutex
}
// New creates a visual videochannel transport backed by a carrier engine.
@@ -388,28 +385,18 @@ func (p *streamTransport) Features() transport.Features {
}
func (p *streamTransport) writeIdleFrame(enc *goEncoder, frameDuration time.Duration) {
p.idleFrameMu.Lock()
cached := p.idleFrame
p.idleFrameMu.Unlock()
if cached == nil {
rawFrame, err := p.renderFrame(nil)
if err != nil {
logger.Debugf("videochannel render idle error: %v", err)
return
}
sample, err := enc.EncodeFrame(rawFrame)
if err != nil {
logger.Warnf("videochannel encoder idle error: %v", err)
return
}
p.idleFrameMu.Lock()
p.idleFrame = sample
p.idleFrameMu.Unlock()
cached = sample
rawFrame, err := p.renderFrame(nil)
if err != nil {
logger.Debugf("videochannel render idle error: %v", err)
return
}
sample, err := enc.EncodeFrame(rawFrame)
if err != nil {
logger.Warnf("videochannel encoder idle error: %v", err)
return
}
_ = p.track.WriteSample(media.Sample{Data: cached, Duration: frameDuration})
_ = p.track.WriteSample(media.Sample{Data: sample, Duration: frameDuration})
}
func (p *streamTransport) writePayloadFrame(enc *goEncoder, payload []byte, frameDuration time.Duration) {