neko/internal/config/capture.go
2021-12-01 22:34:36 +01:00

178 lines
6.3 KiB
Go

package config
import (
"os"
"github.com/pion/webrtc/v3"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"demodesk/neko/internal/types"
"demodesk/neko/internal/types/codec"
"demodesk/neko/internal/utils"
)
type Capture struct {
Display string
VideoCodec codec.RTPCodec
VideoIDs []string
VideoPipelines map[string]types.VideoConfig
AudioDevice string
AudioCodec codec.RTPCodec
AudioPipeline string
BroadcastAudioBitrate int
BroadcastVideoBitrate int
BroadcastPreset string
BroadcastPipeline string
ScreencastEnabled bool
ScreencastRate string
ScreencastQuality string
ScreencastPipeline string
}
func (Capture) Init(cmd *cobra.Command) error {
// audio
cmd.PersistentFlags().String("capture.audio.device", "audio_output.monitor", "audio device to capture")
if err := viper.BindPFlag("capture.audio.device", cmd.PersistentFlags().Lookup("capture.audio.device")); err != nil {
return err
}
cmd.PersistentFlags().String("capture.audio.codec", "opus", "audio codec to be used")
if err := viper.BindPFlag("capture.audio.codec", cmd.PersistentFlags().Lookup("capture.audio.codec")); err != nil {
return err
}
cmd.PersistentFlags().String("capture.audio.pipeline", "", "gstreamer pipeline used for audio streaming")
if err := viper.BindPFlag("capture.audio.pipeline", cmd.PersistentFlags().Lookup("capture.audio.pipeline")); err != nil {
return err
}
// videos
cmd.PersistentFlags().String("capture.video.codec", "vp8", "video codec to be used")
if err := viper.BindPFlag("capture.video.codec", cmd.PersistentFlags().Lookup("capture.video.codec")); err != nil {
return err
}
cmd.PersistentFlags().StringSlice("capture.video.ids", []string{}, "ordered list of video ids")
if err := viper.BindPFlag("capture.video.ids", cmd.PersistentFlags().Lookup("capture.video.ids")); err != nil {
return err
}
cmd.PersistentFlags().String("capture.video.pipelines", "", "pipelines config in JSON used for video streaming")
if err := viper.BindPFlag("capture.video.pipelines", cmd.PersistentFlags().Lookup("capture.video.pipelines")); err != nil {
return err
}
// broadcast
cmd.PersistentFlags().Int("capture.screencast.audio_bitrate", 128, "broadcast audio bitrate in KB/s")
if err := viper.BindPFlag("capture.screencast.audio_bitrate", cmd.PersistentFlags().Lookup("capture.screencast.audio_bitrate")); err != nil {
return err
}
cmd.PersistentFlags().Int("capture.screencast.video_bitrate", 4096, "broadcast video bitrate in KB/s")
if err := viper.BindPFlag("capture.screencast.video_bitrate", cmd.PersistentFlags().Lookup("capture.screencast.video_bitrate")); err != nil {
return err
}
cmd.PersistentFlags().String("capture.screencast.preset", "veryfast", "broadcast speed preset for h264 encoding")
if err := viper.BindPFlag("capture.screencast.preset", cmd.PersistentFlags().Lookup("capture.screencast.preset")); err != nil {
return err
}
cmd.PersistentFlags().String("capture.broadcast.pipeline", "", "gstreamer pipeline used for broadcasting")
if err := viper.BindPFlag("capture.broadcast.pipeline", cmd.PersistentFlags().Lookup("capture.broadcast.pipeline")); err != nil {
return err
}
// screencast
cmd.PersistentFlags().Bool("capture.screencast.enabled", false, "enable screencast")
if err := viper.BindPFlag("capture.screencast.enabled", cmd.PersistentFlags().Lookup("capture.screencast.enabled")); err != nil {
return err
}
cmd.PersistentFlags().String("capture.screencast.rate", "10/1", "screencast frame rate")
if err := viper.BindPFlag("capture.screencast.rate", cmd.PersistentFlags().Lookup("capture.screencast.rate")); err != nil {
return err
}
cmd.PersistentFlags().String("capture.screencast.quality", "60", "screencast JPEG quality")
if err := viper.BindPFlag("capture.screencast.quality", cmd.PersistentFlags().Lookup("capture.screencast.quality")); err != nil {
return err
}
cmd.PersistentFlags().String("capture.screencast.pipeline", "", "gstreamer pipeline used for screencasting")
if err := viper.BindPFlag("capture.screencast.pipeline", cmd.PersistentFlags().Lookup("capture.screencast.pipeline")); err != nil {
return err
}
return nil
}
func (s *Capture) Set() {
var ok bool
// Display is provided by env variable
s.Display = os.Getenv("DISPLAY")
// video
videoCodec := viper.GetString("capture.video.codec")
s.VideoCodec, ok = codec.ParseStr(videoCodec)
if !ok || s.VideoCodec.Type != webrtc.RTPCodecTypeVideo {
log.Warn().Str("codec", videoCodec).Msgf("unknown video codec, using Vp8")
s.VideoCodec = codec.VP8()
}
s.VideoIDs = viper.GetStringSlice("capture.video.ids")
if err := viper.UnmarshalKey("capture.video.pipelines", &s.VideoPipelines, viper.DecodeHook(
utils.JsonStringAutoDecode(s.VideoPipelines),
)); err != nil {
log.Warn().Err(err).Msgf("unable to parse video pipelines")
}
// default video
if len(s.VideoPipelines) == 0 {
log.Warn().Msgf("no video pipelines specified, using defaults")
s.VideoCodec = codec.VP8()
s.VideoPipelines = map[string]types.VideoConfig{
"main": {
GstPipeline: "ximagesrc display-name={display} show-pointer=false use-damage=false " +
"! video/x-raw " +
"! videoconvert " +
"! queue " +
"! vp8enc end-usage=cbr cpu-used=4 threads=4 deadline=1 keyframe-max-dist=25 " +
"! appsink name=appsink",
},
}
s.VideoIDs = []string{"main"}
}
// audio
s.AudioDevice = viper.GetString("capture.audio.device")
s.AudioPipeline = viper.GetString("capture.audio.pipeline")
audioCodec := viper.GetString("capture.audio.codec")
s.AudioCodec, ok = codec.ParseStr(audioCodec)
if !ok || s.AudioCodec.Type != webrtc.RTPCodecTypeAudio {
log.Warn().Str("codec", audioCodec).Msgf("unknown audio codec, using Opus")
s.AudioCodec = codec.Opus()
}
// broadcast
s.BroadcastAudioBitrate = viper.GetInt("capture.broadcast.audio_bitrate")
s.BroadcastVideoBitrate = viper.GetInt("capture.broadcast.video_bitrate")
s.BroadcastPreset = viper.GetString("capture.broadcast.preset")
s.BroadcastPipeline = viper.GetString("capture.broadcast.pipeline")
// screencast
s.ScreencastEnabled = viper.GetBool("capture.screencast.enabled")
s.ScreencastRate = viper.GetString("capture.screencast.rate")
s.ScreencastQuality = viper.GetString("capture.screencast.quality")
s.ScreencastPipeline = viper.GetString("capture.screencast.pipeline")
}