diff --git a/models/media.go b/models/media.go index 8578ef8..76d836f 100644 --- a/models/media.go +++ b/models/media.go @@ -2,6 +2,7 @@ package models import ( "fmt" + "os/exec" "reflect" "strconv" "strings" @@ -40,6 +41,7 @@ type Mediafile struct { seekUsingTsInput bool seekTimeInput string inputPath string + inputPipeCommand *exec.Cmd hideBanner bool outputPath string outputFormat string @@ -198,6 +200,10 @@ func (m *Mediafile) SetInputPath(val string) { m.inputPath = val } +func (m *Mediafile) SetInputPipeCommand(command *exec.Cmd) { + m.inputPipeCommand = command +} + func (m *Mediafile) SetHideBanner(val bool) { m.hideBanner = val } @@ -409,6 +415,10 @@ func (m *Mediafile) InputPath() string { return m.inputPath } +func (m *Mediafile) InputPipeCommand() *exec.Cmd { + return m.inputPipeCommand +} + func (m *Mediafile) HideBanner() bool { return m.hideBanner } @@ -481,6 +491,7 @@ func (m *Mediafile) ToStrCommand() []string { "RtmpLive", "InputInitialOffset", "InputPath", + "InputPipeCommand", "HideBanner", "Aspect", @@ -569,7 +580,17 @@ func (m *Mediafile) ObtainAspect() []string { } func (m *Mediafile) ObtainInputPath() []string { - return []string{"-i", m.inputPath} + if m.inputPath != "" { + return []string{"-i", m.inputPath} + } + return nil +} + +func (m *Mediafile) ObtainInputPipeCommand() []string { + if m.inputPipeCommand != nil { + return []string{"-i", "pipe:0"} + } + return nil } func (m *Mediafile) ObtainHideBanner() []string { diff --git a/transcoder/transcoder.go b/transcoder/transcoder.go index 712ba82..30aa7ea 100644 --- a/transcoder/transcoder.go +++ b/transcoder/transcoder.go @@ -7,13 +7,14 @@ import ( "errors" "fmt" "io" + "os" "os/exec" "regexp" "strconv" "strings" + "github.com/muhammadharis/goffmpeg/models" "github.com/xfrr/goffmpeg/ffmpeg" - "github.com/xfrr/goffmpeg/models" "github.com/xfrr/goffmpeg/utils" ) @@ -78,6 +79,51 @@ func (t Transcoder) GetCommand() []string { return rcommand } +// InitializeTranscoder initializes the fields necessary for a blank transcoder +func (t *Transcoder) InitializeTranscoder() error { + var Metadata models.Metadata + + var err error + cfg := t.configuration + if len(cfg.FfmpegBin) == 0 || len(cfg.FfprobeBin) == 0 { + cfg, err = ffmpeg.Configure() + if err != nil { + return err + } + } + // Set new Mediafile + MediaFile := new(models.Mediafile) + MediaFile.SetMetadata(Metadata) + + // Set transcoder configuration + t.SetMediaFile(MediaFile) + t.SetConfiguration(cfg) + return nil +} + +// SetInputPath sets the input path for transcoding +func (t *Transcoder) SetInputPath(inputPath string) error { + if t.mediafile.InputPipeCommand() != nil { + return errors.New("cannot set an input path when an input pipe command has been set") + } + t.mediafile.SetInputPath(inputPath) + return nil +} + +// CreateInputPipe creates an input pipe for the transcoding process +func (t *Transcoder) CreateInputPipe(cmd *exec.Cmd) error { + if t.mediafile.InputPath() != "" { + return errors.New("cannot set an input pipe when an input path exists") + } + t.mediafile.SetInputPipeCommand(cmd) + return nil +} + +// SetOutputPath sets the output path for transcoding +func (t *Transcoder) SetOutputPath(outputPath string) { + t.mediafile.SetOutputPath(outputPath) +} + // Initialize Init the transcoding process func (t *Transcoder) Initialize(inputPath string, outputPath string) error { var err error @@ -156,6 +202,12 @@ func (t *Transcoder) Run(progress bool) <-chan error { proc.Stdout = out } + // If an input pipe has been set, we get the command and set it as stdin for the transcoding + if t.mediafile.InputPipeCommand() != nil { + proc.Stdin, err = t.mediafile.InputPipeCommand().StdoutPipe() + proc.Stdout = os.Stdout + } + err = proc.Start() t.SetProcess(proc) @@ -165,6 +217,15 @@ func (t *Transcoder) Run(progress bool) <-chan error { close(done) return } + + // Run the pipe-in command if it's been set + if t.mediafile.InputPipeCommand() != nil { + err = t.mediafile.InputPipeCommand().Run() + if err != nil { + err = fmt.Errorf("Failed execution of pipe-in command (%s) with %s", t.mediafile.InputPipeCommand().Args, err) + } + } + err = proc.Wait() if err != nil { err = fmt.Errorf("Failed Finish FFMPEG (%s) with %s message %s", command, err, out.String())