aboutsummaryrefslogtreecommitdiff
path: root/gst/gst.go
diff options
context:
space:
mode:
Diffstat (limited to 'gst/gst.go')
-rw-r--r--gst/gst.go96
1 files changed, 96 insertions, 0 deletions
diff --git a/gst/gst.go b/gst/gst.go
new file mode 100644
index 0000000..f8a5385
--- /dev/null
+++ b/gst/gst.go
@@ -0,0 +1,96 @@
+package gst
+
+/*
+#cgo pkg-config: gstreamer-1.0 gstreamer-app-1.0
+
+#include "gst.h"
+
+*/
+import "C"
+import (
+ "fmt"
+ "io"
+ "sync"
+ "unsafe"
+
+ "github.com/pion/webrtc/v2"
+ "github.com/pion/webrtc/v2/pkg/media"
+)
+
+func init() {
+ go C.gstreamer_send_start_mainloop()
+}
+
+// Pipeline is a wrapper for a GStreamer Pipeline
+type Pipeline struct {
+ Pipeline *C.GstElement
+ audioTrack *webrtc.Track
+ videoTrack *webrtc.Track
+}
+
+var pipeline = &Pipeline{}
+var pipelinesLock sync.Mutex
+
+// CreatePipeline creates a GStreamer Pipeline
+func CreatePipeline(containerPath string, audioTrack, videoTrack *webrtc.Track) *Pipeline {
+ pipelineStr := fmt.Sprintf("filesrc location=\"%s\" ! decodebin name=demux ! queue ! x264enc bframes=0 speed-preset=veryfast key-int-max=60 ! video/x-h264,stream-format=byte-stream ! appsink name=video demux. ! queue ! audioconvert ! audioresample ! opusenc ! appsink name=audio", containerPath)
+
+ pipelineStrUnsafe := C.CString(pipelineStr)
+ defer C.free(unsafe.Pointer(pipelineStrUnsafe))
+
+ pipelinesLock.Lock()
+ defer pipelinesLock.Unlock()
+ pipeline = &Pipeline{
+ Pipeline: C.gstreamer_send_create_pipeline(pipelineStrUnsafe),
+ audioTrack: audioTrack,
+ videoTrack: videoTrack,
+ }
+ return pipeline
+}
+
+// Start starts the GStreamer Pipeline
+func (p *Pipeline) Start() {
+ // This will signal to goHandlePipelineBuffer
+ // and provide a method for cancelling sends.
+ C.gstreamer_send_start_pipeline(p.Pipeline)
+}
+
+// Play sets the pipeline to PLAYING
+func (p *Pipeline) Play() {
+ C.gstreamer_send_play_pipeline(p.Pipeline)
+}
+
+// Pause sets the pipeline to PAUSED
+func (p *Pipeline) Pause() {
+ C.gstreamer_send_pause_pipeline(p.Pipeline)
+}
+
+// SeekToTime seeks on the pipeline
+func (p *Pipeline) SeekToTime(seekPos int64) {
+ C.gstreamer_send_seek(p.Pipeline, C.int64_t(seekPos))
+}
+
+const (
+ videoClockRate = 90000
+ audioClockRate = 48000
+)
+
+//export goHandlePipelineBuffer
+func goHandlePipelineBuffer(buffer unsafe.Pointer, bufferLen C.int, duration C.int, isVideo C.int) {
+ var track *webrtc.Track
+ var samples uint32
+
+ if isVideo == 1 {
+ samples = uint32(videoClockRate * (float32(duration) / 1000000000))
+ track = pipeline.videoTrack
+ } else {
+ samples = uint32(audioClockRate * (float32(duration) / 1000000000))
+ track = pipeline.audioTrack
+ }
+
+ if err := track.WriteSample(media.Sample{Data: C.GoBytes(buffer, bufferLen), Samples: samples}); err != nil && err != io.ErrClosedPipe {
+ panic(err)
+ }
+
+ C.free(buffer)
+}