RTMP Broadcast (WIP)

This commit is contained in:
Craig 2020-04-06 03:42:42 +00:00
parent 23d645f205
commit 82ca6e13ca
4 changed files with 105 additions and 5 deletions

View File

@ -0,0 +1,40 @@
package broadcast
import (
"github.com/rs/zerolog"
"n.eko.moe/neko/internal/gst"
"n.eko.moe/neko/internal/types/config"
)
type BroadcastManager struct {
logger zerolog.Logger
pipeline *gst.Pipeline
config *config.Broadcast
}
func New(config *config.Broadcast) *BroadcastManager {
return &BroadcastManager{
logger: log.With().Str("module", "remote").Logger(),
config: config
}
}
func (manager *BroadcastManager) Start() {
var err error
manager.pipeline, err = gst.CreateRTMPPipeline(
manager.config.Device,
manager.config.Display,
manager.config.RTMP,
)
if err != nil {
manager.logger.Panic().Err(err).Msg("unable to create rtmp pipeline")
}
manager.pipeline.Start()
}
func (manager *BroadcastManager) Shutdown() error {
if (manager.pipeline != nil) {
manager.pipeline.Stop()
}
}

View File

@ -64,8 +64,15 @@ func init() {
registry = C.gst_registry_get() registry = C.gst_registry_get()
} }
// CreatePipeline creates a GStreamer Pipeline // CreateRTMPPipeline creates a GStreamer Pipeline
func CreatePipeline(codecName string, pipelineDevice string, pipelineSrc string) (*Pipeline, error) { func CreateRTMPPipeline(pipelineDevice string, pipelineDisplay string, pipelineRTMP string) (*Pipeline, error) {
video := fmt.Sprintf(videoSrc, pipelineDisplay)
audio := fmt.Sprintf(audioSrc, pipelineDevice)
return CreatePipeline(fmt.Sprintf("%s ! x264enc ! flv. ! %s ! faac ! flv. ! flvmux name='flv' ! rtmpsink location='%s'", video, audio, pipelineRTMP))
}
// CreateAppPipeline creates a GStreamer Pipeline
func CreateAppPipeline(codecName string, pipelineDevice string, pipelineSrc string) (*Pipeline, error) {
pipelineStr := " ! appsink name=appsink" pipelineStr := " ! appsink name=appsink"
var clockRate float32 var clockRate float32
@ -192,6 +199,11 @@ func CreatePipeline(codecName string, pipelineDevice string, pipelineSrc string)
return nil, fmt.Errorf("unknown codec %s", codecName) return nil, fmt.Errorf("unknown codec %s", codecName)
} }
return CreatePipeline(pipelineStr)
}
// CreatePipeline creates a GStreamer Pipeline
func CreatePipeline(pipelineStr string) (*Pipeline, error) {
pipelineStrUnsafe := C.CString(pipelineStr) pipelineStrUnsafe := C.CString(pipelineStr)
defer C.free(unsafe.Pointer(pipelineStrUnsafe)) defer C.free(unsafe.Pointer(pipelineStrUnsafe))

View File

@ -127,7 +127,7 @@ func (manager *RemoteManager) Streaming() bool {
func (manager *RemoteManager) createPipelines() { func (manager *RemoteManager) createPipelines() {
var err error var err error
manager.video, err = gst.CreatePipeline( manager.video, err = gst.CreateAppPipeline(
manager.config.VideoCodec, manager.config.VideoCodec,
manager.config.Display, manager.config.Display,
manager.config.VideoParams, manager.config.VideoParams,
@ -136,7 +136,7 @@ func (manager *RemoteManager) createPipelines() {
manager.logger.Panic().Err(err).Msg("unable to create video pipeline") manager.logger.Panic().Err(err).Msg("unable to create video pipeline")
} }
manager.audio, err = gst.CreatePipeline( manager.audio, err = gst.CreateAppPipeline(
manager.config.AudioCodec, manager.config.AudioCodec,
manager.config.Device, manager.config.Device,
manager.config.AudioParams, manager.config.AudioParams,
@ -161,7 +161,7 @@ func (manager *RemoteManager) ChangeResolution(width int, height int, rate int)
return err return err
} }
video, err := gst.CreatePipeline( video, err := gst.CreateAppPipeline(
manager.config.VideoCodec, manager.config.VideoCodec,
manager.config.Display, manager.config.Display,
manager.config.VideoParams, manager.config.VideoParams,

View File

@ -0,0 +1,48 @@
package config
import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
type Broadcast struct {
Enabled string
Display string
Device string
AudioParams string
VideoParams string
RTMP string
}
func (Broadcast) Init(cmd *cobra.Command) error {
cmd.PersistentFlags().Bool("broadcast", false, "use PCMA audio codec")
if err := viper.BindPFlag("broadcast", cmd.PersistentFlags().Lookup("broadcast")); err != nil {
return err
}
cmd.PersistentFlags().String("rtmp", "", "RMTP url for broadcasting")
if err := viper.BindPFlag("rtmp", cmd.PersistentFlags().Lookup("rtmp")); err != nil {
return err
}
cmd.PersistentFlags().String("cast_audio", "", "audio codec parameters to use for broadcasting")
if err := viper.BindPFlag("cast_audio", cmd.PersistentFlags().Lookup("cast_audio")); err != nil {
return err
}
cmd.PersistentFlags().String("cast_video", "", "video codec parameters to use for broadcasting")
if err := viper.BindPFlag("cast_video", cmd.PersistentFlags().Lookup("cast_video")); err != nil {
return err
}
return nil
}
func (s *Broadcast) Set() {
s.Enabled = viper.GetBool("broadcast")
s.Display = viper.GetString("display")
s.Device = viper.GetString("device")
s.AudioParams = viper.GetString("cast_audio")
s.VideoParams = viper.GetString("cast_video")
s.RTMP = viper.GetString("rtmp")
}