From c0c14b3ac22b2fd6417d0a4f897d9d8e5edfea24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= Date: Tue, 9 Feb 2021 20:36:22 +0100 Subject: [PATCH] add screen-size aware pipelines. --- internal/capture/manager.go | 127 +++++++++++++++++++++++------------- internal/capture/stream.go | 9 +-- 2 files changed, 87 insertions(+), 49 deletions(-) diff --git a/internal/capture/manager.go b/internal/capture/manager.go index a6c7267a..4bce6cdc 100644 --- a/internal/capture/manager.go +++ b/internal/capture/manager.go @@ -3,6 +3,7 @@ package capture import ( "fmt" "sync" + "math" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -58,58 +59,94 @@ func New(desktop types.DesktopManager, config *config.Capture) *CaptureManagerCt ) } - audioPipeline := config.AudioPipeline - if audioPipeline == "" { - audioPipeline = fmt.Sprintf( - "pulsesrc device=%s " + - "! audio/x-raw,channels=2 " + - "! audioconvert " + - "! queue " + - "! %s " + - "! appsink name=appsink", config.Device, config.AudioCodec.Pipeline, - ) - } - return &CaptureManagerCtx{ logger: logger, desktop: desktop, streaming: false, broadcast: broadcastNew(broadcastPipeline), screencast: screencastNew(config.Screencast, screencastPipeline), - audio: streamNew(config.AudioCodec, audioPipeline), + audio: streamNew(config.AudioCodec, func() string { + if config.AudioPipeline != "" { + return config.AudioPipeline + } + + return fmt.Sprintf( + "pulsesrc device=%s " + + "! audio/x-raw,channels=2 " + + "! audioconvert " + + "! queue " + + "! %s " + + "! appsink name=appsink", config.Device, config.AudioCodec.Pipeline, + ) + }), videos: map[string]*StreamManagerCtx{ - "hd": streamNew(codec.VP8(), fmt.Sprintf( - "ximagesrc display-name=%s show-pointer=false use-damage=false " + - "! video/x-raw,framerate=25/1 " + - "! videoconvert " + - "! queue " + - "! vp8enc target-bitrate=24576000 cpu-used=16 threads=4 deadline=1 error-resilient=partitions keyframe-max-dist=15 static-threshold=20 " + - "! appsink name=appsink", config.Display, - )), - "hq": streamNew(codec.VP8(), fmt.Sprintf( - "ximagesrc display-name=%s show-pointer=false use-damage=false " + - "! video/x-raw,framerate=25/1 " + - "! videoconvert " + - "! queue " + - "! vp8enc target-bitrate=16588800 cpu-used=16 threads=4 deadline=1 error-resilient=partitions keyframe-max-dist=15 static-threshold=20 " + - "! appsink name=appsink", config.Display, - )), - "mq": streamNew(codec.VP8(), fmt.Sprintf( - "ximagesrc display-name=%s show-pointer=false use-damage=false " + - "! video/x-raw,framerate=125/10 " + - "! videoconvert " + - "! queue " + - "! vp8enc target-bitrate=9216000 cpu-used=16 threads=4 deadline=1 error-resilient=partitions keyframe-max-dist=15 static-threshold=20 " + - "! appsink name=appsink", config.Display, - )), - "lq": streamNew(codec.VP8(), fmt.Sprintf( - "ximagesrc display-name=%s show-pointer=false use-damage=false " + - "! video/x-raw,framerate=125/10 " + - "! videoconvert " + - "! queue " + - "! vp8enc target-bitrate=4608000 cpu-used=16 threads=4 deadline=1 error-resilient=partitions keyframe-max-dist=15 static-threshold=20 " + - "! appsink name=appsink", config.Display, - )), + "hd": streamNew(codec.VP8(), func() string { + screen := desktop.GetScreenSize() + bitrate := screen.Width * screen.Height * 12 + + return fmt.Sprintf( + "ximagesrc display-name=%s show-pointer=false use-damage=false " + + "! video/x-raw,framerate=25/1 " + + "! videoconvert " + + "! queue " + + "! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=6 max-quantizer=12 " + + "! appsink name=appsink", config.Display, bitrate, + ) + }), + "hq": streamNew(codec.VP8(), func() string { + screen := desktop.GetScreenSize() + width := int(math.Ceil(float64(screen.Width) / 6) * 5) + height := int(math.Ceil(float64(screen.Height) / 6) * 5) + bitrate := width * height * 12 + + return fmt.Sprintf( + "ximagesrc display-name=%s show-pointer=false use-damage=false " + + "! video/x-raw,framerate=25/1 " + + "! videoconvert " + + "! queue " + + "! videoscale " + + "! video/x-raw,width=%d,height=%d " + + "! queue " + + "! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=6 max-quantizer=12 " + + "! appsink name=appsink", config.Display, width, height, bitrate, + ) + }), + "mq": streamNew(codec.VP8(), func() string { + screen := desktop.GetScreenSize() + width := int(math.Ceil(float64(screen.Width) / 6) * 4) + height := int(math.Ceil(float64(screen.Height) / 6) * 4) + bitrate := width * height * 8 + + return fmt.Sprintf( + "ximagesrc display-name=%s show-pointer=false use-damage=false " + + "! video/x-raw,framerate=125/10 " + + "! videoconvert " + + "! queue " + + "! videoscale " + + "! video/x-raw,width=%d,height=%d " + + "! queue " + + "! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=12 max-quantizer=24 " + + "! appsink name=appsink", config.Display, width, height, bitrate, + ) + }), + "lq": streamNew(codec.VP8(), func() string { + screen := desktop.GetScreenSize() + width := int(math.Ceil(float64(screen.Width) / 6) * 3) + height := int(math.Ceil(float64(screen.Height) / 6) * 3) + bitrate := width * height * 4 + + return fmt.Sprintf( + "ximagesrc display-name=%s show-pointer=false use-damage=false " + + "! video/x-raw,framerate=125/10 " + + "! videoconvert " + + "! queue " + + "! videoscale " + + "! video/x-raw,width=%d,height=%d " + + "! queue " + + "! vp8enc target-bitrate=%d cpu-used=16 threads=4 deadline=100000 error-resilient=partitions keyframe-max-dist=15 auto-alt-ref=true min-quantizer=12 max-quantizer=24 " + + "! appsink name=appsink", config.Display, width, height, bitrate, + ) + }), }, videoIDs: []string{ "hd", "hq", "mq", "lq" }, } diff --git a/internal/capture/stream.go b/internal/capture/stream.go index e4c366cf..61d6ef80 100644 --- a/internal/capture/stream.go +++ b/internal/capture/stream.go @@ -17,7 +17,7 @@ type StreamManagerCtx struct { logger zerolog.Logger mu sync.Mutex codec codec.RTPCodec - pipelineStr string + pipelineStr func() string pipeline *gst.Pipeline sample chan types.Sample listeners map[uintptr]*func(sample types.Sample) @@ -27,7 +27,7 @@ type StreamManagerCtx struct { started bool } -func streamNew(codec codec.RTPCodec, pipelineStr string) *StreamManagerCtx { +func streamNew(codec codec.RTPCodec, pipelineStr func() string) *StreamManagerCtx { manager := &StreamManagerCtx{ logger: log.With().Str("module", "capture").Str("submodule", "stream").Logger(), codec: codec, @@ -132,12 +132,13 @@ func (manager *StreamManagerCtx) createPipeline() error { var err error codec := manager.Codec() + pipelineStr := manager.pipelineStr() manager.logger.Info(). Str("codec", codec.Name). - Str("src", manager.pipelineStr). + Str("src", pipelineStr). Msgf("creating pipeline") - manager.pipeline, err = gst.CreatePipeline(manager.pipelineStr) + manager.pipeline, err = gst.CreatePipeline(pipelineStr) if err != nil { return err }