178 lines
5.4 KiB
Go
178 lines
5.4 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"git.entr0py.de/garionion/gstreamer-graphix/gstreamer"
|
|
"github.com/google/uuid"
|
|
"github.com/rs/zerolog/log"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type PipelineService struct {
|
|
pipelineSlots map[string][]string
|
|
pipelineslotmapping map[string]string
|
|
UnimplementedPipelineServiceServer
|
|
*gstreamer.Gstreamer
|
|
Font, FontWeight string //default font
|
|
FontSize int // Fontsize 0 does not make sense
|
|
Context context.Context
|
|
sync.RWMutex
|
|
}
|
|
|
|
func (s *PipelineService) UpdatePipeline(ctx context.Context, updates *PipelineUpdates) (*PipelineUpdateResponse, error) {
|
|
pipeline, err := s.Gstreamer.GetPipeline(updates.Id.GetId())
|
|
if err != nil {
|
|
log.Error().Str("ID", updates.Id.GetId()).Err(err)
|
|
} else {
|
|
overlays := s.convertRPCOverlayToGstreamerOverlay(updates.GetOverlays())
|
|
s.Lock()
|
|
pipeline.PipelineUpdates <- gstreamer.PipelineUpdates{Overlays: overlays}
|
|
s.Unlock()
|
|
}
|
|
|
|
return &PipelineUpdateResponse{PipelineId: &PipelineID{Id: updates.Id.GetId()}}, nil
|
|
}
|
|
|
|
func (s *PipelineService) StopPipeline(ctx context.Context, id *PipelineID) (*PipelineStopResponse, error) {
|
|
pipeline, err := s.Gstreamer.GetPipeline(id.GetId())
|
|
if err != nil {
|
|
log.Error().Str("ID", id.GetId()).Err(err)
|
|
} else {
|
|
pipeline.Lock()
|
|
err = pipeline.Stop()
|
|
pipeline.Unlock()
|
|
}
|
|
return &PipelineStopResponse{PipelineId: &PipelineID{Id: id.GetId()}}, err
|
|
}
|
|
|
|
func (s *PipelineService) StartPipeline(ctx context.Context, id *PipelineID) (*PipelineStartResponse, error) {
|
|
pipeline, err := s.Gstreamer.GetPipeline(id.GetId())
|
|
if err != nil {
|
|
log.Error().Str("ID", id.GetId()).Err(err)
|
|
} else {
|
|
pipeline.Lock()
|
|
err = pipeline.Start()
|
|
pipeline.Unlock()
|
|
}
|
|
return &PipelineStartResponse{PipelineId: &PipelineID{Id: id.GetId()}}, err
|
|
}
|
|
|
|
func (s *PipelineService) DeletePipeline(ctx context.Context, id *PipelineID) (*PipelineDeleteResponse, error) {
|
|
s.Gstreamer.DeletePipeline(id.GetId())
|
|
var err error
|
|
if slot, ok := s.pipelineslotmapping[id.GetId()]; ok {
|
|
s.Lock()
|
|
defer s.Unlock()
|
|
delete(s.pipelineslotmapping, id.GetId())
|
|
var i int
|
|
for i := range s.pipelineSlots[slot] {
|
|
if s.pipelineSlots[slot][i] == id.GetId() {
|
|
break
|
|
}
|
|
}
|
|
s.pipelineSlots[slot] = append(s.pipelineSlots[slot][:i], s.pipelineSlots[slot][i+1:]...)
|
|
} else {
|
|
err = fmt.Errorf("Pipeline %s not found", id.GetId())
|
|
}
|
|
return &PipelineDeleteResponse{PipelineId: &PipelineID{Id: id.GetId()}}, err
|
|
}
|
|
|
|
func (s *PipelineService) CreatePipeline(ctx context.Context, pipeline *Pipeline) (*PipelineCreationResponse, error) {
|
|
uid, _ := uuid.NewRandom()
|
|
id := uid.String()
|
|
gstreamerPipeline := &gstreamer.Pipeline{
|
|
Name: pipeline.GetName(),
|
|
ID: id,
|
|
InputElement: gstreamer.InputElement{
|
|
Name: fmt.Sprintf("%s-input", pipeline.GetName()),
|
|
Type: "filesrc",
|
|
Properties: map[string]string{
|
|
"location": pipeline.GetClip(),
|
|
},
|
|
},
|
|
OutputElement: gstreamer.OutputElement{
|
|
Name: fmt.Sprintf("%s-output", pipeline.GetName()),
|
|
Type: pipeline.GetOutput(),
|
|
},
|
|
}
|
|
gstreamerPipeline.Overlays = s.convertRPCOverlayToGstreamerOverlay(pipeline.Overlays)
|
|
_, err := gstreamerPipeline.Create()
|
|
if err != nil {
|
|
log.Error().Err(err)
|
|
return nil, err
|
|
}
|
|
s.Lock()
|
|
if s.pipelineSlots == nil {
|
|
s.pipelineSlots = make(map[string][]string)
|
|
}
|
|
if _, ok := s.pipelineSlots[pipeline.GetName()]; ok {
|
|
s.pipelineSlots[pipeline.GetName()] = append(s.pipelineSlots[pipeline.GetName()], id)
|
|
} else {
|
|
s.pipelineSlots[pipeline.GetName()] = []string{id}
|
|
}
|
|
if s.pipelineslotmapping == nil {
|
|
s.pipelineslotmapping = make(map[string]string)
|
|
}
|
|
s.pipelineslotmapping[id] = pipeline.GetName()
|
|
s.Unlock()
|
|
return &PipelineCreationResponse{
|
|
PipelineId: &PipelineID{Id: id},
|
|
}, nil
|
|
}
|
|
|
|
func (s *PipelineService) convertRPCOverlayToGstreamerOverlay(apiOverlays []*Overlay) map[string]gstreamer.Overlay {
|
|
gstreamerOverlays := map[string]gstreamer.Overlay{}
|
|
for _, overlay := range apiOverlays {
|
|
switch overlay.GetOverlayData().(type) {
|
|
case *Overlay_Extra:
|
|
log.Error().Msgf("Extra Element not implemented, used by overlay %s", overlay.GetName())
|
|
case *Overlay_ImageOverlay:
|
|
o := overlay.GetImageOverlay()
|
|
imageOverlay := &gstreamer.ImageOverlay{
|
|
Name: overlay.GetName(),
|
|
Path: o.GetPath(),
|
|
X: int(overlay.GetX()),
|
|
Y: int(overlay.GetY()),
|
|
Display: overlay.GetDisplay(),
|
|
BlendIn: time.Duration(overlay.GetBlendIn()),
|
|
BlendOut: time.Duration(overlay.GetBlendOut()),
|
|
}
|
|
gstreamerOverlays[overlay.GetName()] = imageOverlay
|
|
case *Overlay_TextOverlay:
|
|
o := overlay.GetTextOverlay()
|
|
if o.GetText() == "" {
|
|
continue
|
|
}
|
|
font := s.Font
|
|
if o.GetFontName() != "" {
|
|
font = o.GetFontName()
|
|
}
|
|
fontsize := s.FontSize
|
|
if o.GetFontSize() != 0 {
|
|
fontsize = int(o.GetFontSize())
|
|
}
|
|
fontweight := s.FontWeight
|
|
if o.GetFontWeight() != "" {
|
|
font = o.GetFontWeight()
|
|
}
|
|
textOverlay := &gstreamer.TextOverlay{
|
|
Name: overlay.GetName(),
|
|
X: int(overlay.GetX()),
|
|
Y: int(overlay.GetY()),
|
|
Font: font,
|
|
FontSize: fontsize,
|
|
FontWeight: fontweight,
|
|
Color: o.GetFontColor(),
|
|
Value: o.GetText(),
|
|
Display: overlay.GetDisplay(),
|
|
MaxWidth: uint(o.GetMaxWidth()),
|
|
BlendIn: time.Duration(overlay.GetBlendIn()),
|
|
BlendOut: time.Duration(overlay.GetBlendOut()),
|
|
}
|
|
gstreamerOverlays[overlay.GetName()] = textOverlay
|
|
}
|
|
}
|
|
return gstreamerOverlays
|
|
}
|