Live video on the AT Protocol
at eli/database-resync 84 lines 2.0 kB view raw
1package media 2 3import ( 4 "context" 5 "fmt" 6 "io" 7 "strings" 8 9 "github.com/go-gst/go-gst/gst" 10 "github.com/go-gst/go-gst/gst/app" 11 "stream.place/streamplace/pkg/log" 12) 13 14func Thumbnail(ctx context.Context, r io.Reader, w io.Writer, format string) error { 15 ctx = log.WithLogValues(ctx, "function", "Thumbnail") 16 ctx, cancel := context.WithCancel(ctx) 17 defer cancel() 18 19 var encoder string 20 switch format { 21 case "jpeg": 22 encoder = "jpegenc snapshot=true" 23 case "png": 24 encoder = "pngenc snapshot=true" 25 default: 26 log.Error(ctx, "media.Thumbnail: expected jpeg or png as format and recieved %s", format) 27 encoder = "pngenc snapshot=true" 28 } 29 30 pipelineSlice := []string{ 31 "appsrc name=appsrc ! qtdemux name=demux ! decodebin ! videoconvert ! videoscale ! videorate ! capsfilter name=capsfilter caps=video/x-raw,width=[1,1280],height=[1,720],pixel-aspect-ratio=1/1,framerate=1/999999 ! queue ! ", 32 encoder, 33 " ! appsink name=appsink", 34 } 35 36 pipeline, err := gst.NewPipelineFromString(strings.Join(pipelineSlice, "\n")) 37 if err != nil { 38 return fmt.Errorf("error creating Thumbnail pipeline: %w", err) 39 } 40 41 defer func() { 42 cancel() 43 err = pipeline.BlockSetState(gst.StateNull) 44 }() 45 appsrc, err := pipeline.GetElementByName("appsrc") 46 if err != nil { 47 return err 48 } 49 50 src := app.SrcFromElement(appsrc) 51 src.SetCallbacks(&app.SourceCallbacks{ 52 NeedDataFunc: ReaderNeedData(ctx, r), 53 }) 54 55 appsink, err := pipeline.GetElementByName("appsink") 56 if err != nil { 57 return err 58 } 59 60 errCh := make(chan error) 61 go func() { 62 err := HandleBusMessages(ctx, pipeline) 63 cancel() 64 errCh <- err 65 close(errCh) 66 }() 67 68 sink := app.SinkFromElement(appsink) 69 sink.SetCallbacks(&app.SinkCallbacks{ 70 NewSampleFunc: WriterNewSample(ctx, w), 71 }) 72 73 if err := pipeline.BlockSetState(gst.StatePlaying); err != nil { 74 return fmt.Errorf("error setting pipeline state: %w", err) 75 } 76 77 <-ctx.Done() 78 79 if err := pipeline.BlockSetState(gst.StateNull); err != nil { 80 return fmt.Errorf("error setting pipeline state: %w", err) 81 } 82 83 return <-errCh 84}