mirror of
https://github.com/xfrr/goffmpeg.git
synced 2026-04-22 23:17:21 +08:00
Merge branch 'master' into AES-Encryption
This commit is contained in:
@@ -77,6 +77,7 @@ func main() {
|
||||
```
|
||||
|
||||
## How to pipe in data using the [pipe protocol](https://ffmpeg.org/ffmpeg-protocols.html#pipe)
|
||||
Creating an input pipe will return [\*io.PipeReader](https://golang.org/pkg/io/#PipeReader), and creating an output pipe will return [\*io.PipeWriter](https://golang.org/pkg/io/#PipeWriter). An example is shown which uses `cat` to pipe in data, and [ioutil.ReadAll](https://golang.org/pkg/io/ioutil/#ReadAll) to read data as bytes from the pipe.
|
||||
```go
|
||||
func main() {
|
||||
|
||||
@@ -87,19 +88,43 @@ func main() {
|
||||
err := trans.InitializeEmptyTranscoder()
|
||||
// Handle error...
|
||||
|
||||
// Set the output path on the transcoder
|
||||
trans.SetOutputPath("/tmp/data/out/output.mp4")
|
||||
// Create a command such that its output should be passed as stdin to ffmpeg
|
||||
cmd := exec.Command("cat", "/path/to/file")
|
||||
|
||||
// Set a command such that its output should be passed as stdin to ffmpeg
|
||||
err = trans.CreateInputPipe(exec.Command("cat", "/tmp/data/testmpeg"))
|
||||
// Handle error...
|
||||
// Create an input pipe to write to, which will return *io.PipeWriter
|
||||
w, err := trans.CreateInputPipe()
|
||||
|
||||
cmd.Stdout = w
|
||||
|
||||
// Create an output pipe to read from, which will return *io.PipeReader.
|
||||
// Must also specify the output container format
|
||||
r, err := trans.CreateOutputPipe("mp4")
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer r.Close()
|
||||
defer wg.Done()
|
||||
|
||||
// Read data from output pipe
|
||||
data, err := ioutil.ReadAll(r)
|
||||
// Handle error and data...
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer w.Close()
|
||||
err := cmd.Run()
|
||||
// Handle error...
|
||||
}()
|
||||
|
||||
// Start transcoder process without checking progress
|
||||
done := trans.Run(true)
|
||||
done := trans.Run(false)
|
||||
|
||||
// This channel is used to wait for the transcoding process to end
|
||||
err = <-done
|
||||
// Handle error...
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -156,6 +181,8 @@ SetRtmpLive
|
||||
SetHlsListSize
|
||||
SetHlsSegmentDuration
|
||||
SetHlsPlaylistType
|
||||
SetHlsMasterPlaylistName
|
||||
SetHlsSegmentFilename
|
||||
SetHttpMethod
|
||||
SetHttpKeepAlive
|
||||
SetOutputPath
|
||||
|
||||
+198
-25
@@ -2,7 +2,7 @@ package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
type Mediafile struct {
|
||||
aspect string
|
||||
resolution string
|
||||
videoBitRate int
|
||||
videoBitRate string
|
||||
videoBitRateTolerance int
|
||||
videoMaxBitRate int
|
||||
videoMinBitrate int
|
||||
@@ -27,6 +27,7 @@ type Mediafile struct {
|
||||
audioChannels int
|
||||
audioVariableBitrate bool
|
||||
bufferSize int
|
||||
threadset bool
|
||||
threads int
|
||||
preset string
|
||||
tune string
|
||||
@@ -36,13 +37,20 @@ type Mediafile struct {
|
||||
duration string
|
||||
durationInput string
|
||||
seekTime string
|
||||
quality int
|
||||
qscale uint32
|
||||
crf uint32
|
||||
strict int
|
||||
muxDelay string
|
||||
seekUsingTsInput bool
|
||||
seekTimeInput string
|
||||
inputPath string
|
||||
inputPipeCommand *exec.Cmd
|
||||
inputPipe bool
|
||||
inputPipeReader *io.PipeReader
|
||||
inputPipeWriter *io.PipeWriter
|
||||
outputPipe bool
|
||||
outputPipeReader *io.PipeReader
|
||||
outputPipeWriter *io.PipeWriter
|
||||
movFlags string
|
||||
hideBanner bool
|
||||
outputPath string
|
||||
outputFormat string
|
||||
@@ -53,8 +61,11 @@ type Mediafile struct {
|
||||
hlsPlaylistType string
|
||||
hlsListSize int
|
||||
hlsSegmentDuration int
|
||||
hlsMasterPlaylistName string
|
||||
hlsSegmentFilename string
|
||||
httpMethod string
|
||||
httpKeepAlive bool
|
||||
hwaccel string
|
||||
streamIds map[int]string
|
||||
metadata Metadata
|
||||
videoFilter string
|
||||
@@ -62,6 +73,8 @@ type Mediafile struct {
|
||||
skipVideo bool
|
||||
skipAudio bool
|
||||
encryptionKey string
|
||||
movflags string
|
||||
bframe int
|
||||
pixFmt string
|
||||
}
|
||||
|
||||
@@ -87,7 +100,7 @@ func (m *Mediafile) SetResolution(v string) {
|
||||
m.resolution = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetVideoBitRate(v int) {
|
||||
func (m *Mediafile) SetVideoBitRate(v string) {
|
||||
m.videoBitRate = v
|
||||
}
|
||||
|
||||
@@ -156,6 +169,7 @@ func (m *Mediafile) SetBufferSize(v int) {
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetThreads(v int) {
|
||||
m.threadset = true
|
||||
m.threads = v
|
||||
}
|
||||
|
||||
@@ -191,8 +205,13 @@ func (m *Mediafile) SetSeekTimeInput(v string) {
|
||||
m.seekTimeInput = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetQuality(v int) {
|
||||
m.quality = v
|
||||
// Q Scale must be integer between 1 to 31 - https://trac.ffmpeg.org/wiki/Encode/MPEG-4
|
||||
func (m *Mediafile) SetQScale(v uint32) {
|
||||
m.qscale = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetCRF(v uint32) {
|
||||
m.crf = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetStrict(v int) {
|
||||
@@ -211,8 +230,32 @@ func (m *Mediafile) SetInputPath(val string) {
|
||||
m.inputPath = val
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetInputPipeCommand(command *exec.Cmd) {
|
||||
m.inputPipeCommand = command
|
||||
func (m *Mediafile) SetInputPipe(val bool) {
|
||||
m.inputPipe = val
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetInputPipeReader(r *io.PipeReader) {
|
||||
m.inputPipeReader = r
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetInputPipeWriter(w *io.PipeWriter) {
|
||||
m.inputPipeWriter = w
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetOutputPipe(val bool) {
|
||||
m.outputPipe = val
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetOutputPipeReader(r *io.PipeReader) {
|
||||
m.outputPipeReader = r
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetOutputPipeWriter(w *io.PipeWriter) {
|
||||
m.outputPipeWriter = w
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetMovFlags(val string) {
|
||||
m.movFlags = val
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetHideBanner(val bool) {
|
||||
@@ -251,6 +294,14 @@ func (m *Mediafile) SetHlsPlaylistType(val string) {
|
||||
m.hlsPlaylistType = val
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetHlsMasterPlaylistName(val string) {
|
||||
m.hlsMasterPlaylistName = val
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetHlsSegmentFilename(val string) {
|
||||
m.hlsSegmentFilename = val
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetHttpMethod(val string) {
|
||||
m.httpMethod = val
|
||||
}
|
||||
@@ -259,6 +310,10 @@ func (m *Mediafile) SetHttpKeepAlive(val bool) {
|
||||
m.httpKeepAlive = val
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetHardwareAcceleration(val string) {
|
||||
m.hwaccel = val
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetInputInitialOffset(val string) {
|
||||
m.inputInitialOffset = val
|
||||
}
|
||||
@@ -279,6 +334,14 @@ func (m *Mediafile) SetMetadata(v Metadata) {
|
||||
m.metadata = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetMovFlags(v string) {
|
||||
m.movflags = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetBframe(v int) {
|
||||
m.bframe = v
|
||||
}
|
||||
|
||||
/*** GETTERS ***/
|
||||
|
||||
// Deprecated: Use VideoFilter instead.
|
||||
@@ -302,7 +365,7 @@ func (m *Mediafile) Resolution() string {
|
||||
return m.resolution
|
||||
}
|
||||
|
||||
func (m *Mediafile) VideoBitrate() int {
|
||||
func (m *Mediafile) VideoBitrate() string {
|
||||
return m.videoBitRate
|
||||
}
|
||||
|
||||
@@ -406,8 +469,12 @@ func (m *Mediafile) SeekTimeInput() string {
|
||||
return m.seekTimeInput
|
||||
}
|
||||
|
||||
func (m *Mediafile) Quality() int {
|
||||
return m.quality
|
||||
func (m *Mediafile) QScale() uint32 {
|
||||
return m.qscale
|
||||
}
|
||||
|
||||
func (m *Mediafile) CRF() uint32 {
|
||||
return m.crf
|
||||
}
|
||||
|
||||
func (m *Mediafile) Strict() int {
|
||||
@@ -430,8 +497,32 @@ func (m *Mediafile) InputPath() string {
|
||||
return m.inputPath
|
||||
}
|
||||
|
||||
func (m *Mediafile) InputPipeCommand() *exec.Cmd {
|
||||
return m.inputPipeCommand
|
||||
func (m *Mediafile) InputPipe() bool {
|
||||
return m.inputPipe
|
||||
}
|
||||
|
||||
func (m *Mediafile) InputPipeReader() *io.PipeReader {
|
||||
return m.inputPipeReader
|
||||
}
|
||||
|
||||
func (m *Mediafile) InputPipeWriter() *io.PipeWriter {
|
||||
return m.inputPipeWriter
|
||||
}
|
||||
|
||||
func (m *Mediafile) OutputPipe() bool {
|
||||
return m.outputPipe
|
||||
}
|
||||
|
||||
func (m *Mediafile) OutputPipeReader() *io.PipeReader {
|
||||
return m.outputPipeReader
|
||||
}
|
||||
|
||||
func (m *Mediafile) OutputPipeWriter() *io.PipeWriter {
|
||||
return m.outputPipeWriter
|
||||
}
|
||||
|
||||
func (m *Mediafile) MovFlags() string {
|
||||
return m.movFlags
|
||||
}
|
||||
|
||||
func (m *Mediafile) HideBanner() bool {
|
||||
@@ -462,6 +553,14 @@ func (m *Mediafile) HlsSegmentDuration() int {
|
||||
return m.hlsSegmentDuration
|
||||
}
|
||||
|
||||
func (m *Mediafile) HlsMasterPlaylistName() string {
|
||||
return m.hlsMasterPlaylistName
|
||||
}
|
||||
|
||||
func (m *Mediafile) HlsSegmentFilename() string {
|
||||
return m.hlsSegmentFilename
|
||||
}
|
||||
|
||||
func (m *Mediafile) HlsPlaylistType() string {
|
||||
return m.hlsPlaylistType
|
||||
}
|
||||
@@ -478,6 +577,10 @@ func (m *Mediafile) HttpKeepAlive() bool {
|
||||
return m.httpKeepAlive
|
||||
}
|
||||
|
||||
func (m *Mediafile) HardwareAcceleration() string {
|
||||
return m.hwaccel
|
||||
}
|
||||
|
||||
func (m *Mediafile) StreamIds() map[int]string {
|
||||
return m.streamIds
|
||||
}
|
||||
@@ -513,8 +616,9 @@ func (m *Mediafile) ToStrCommand() []string {
|
||||
"DurationInput",
|
||||
"RtmpLive",
|
||||
"InputInitialOffset",
|
||||
"HardwareAcceleration",
|
||||
"InputPath",
|
||||
"InputPipeCommand",
|
||||
"InputPipe",
|
||||
"HideBanner",
|
||||
|
||||
"Aspect",
|
||||
@@ -534,7 +638,8 @@ func (m *Mediafile) ToStrCommand() []string {
|
||||
"AudioChannels",
|
||||
"AudioProfile",
|
||||
"SkipAudio",
|
||||
"Quality",
|
||||
"CRF",
|
||||
"QScale",
|
||||
"Strict",
|
||||
"BufferSize",
|
||||
"MuxDelay",
|
||||
@@ -548,16 +653,22 @@ func (m *Mediafile) ToStrCommand() []string {
|
||||
"Duration",
|
||||
"CopyTs",
|
||||
"StreamIds",
|
||||
"MovFlags",
|
||||
"OutputFormat",
|
||||
"OutputPipe",
|
||||
"HlsListSize",
|
||||
"HlsSegmentDuration",
|
||||
"HlsPlaylistType",
|
||||
"HlsMasterPlaylistName",
|
||||
"HlsSegmentFilename",
|
||||
"AudioFilter",
|
||||
"VideoFilter",
|
||||
"HttpMethod",
|
||||
"HttpKeepAlive",
|
||||
"EncryptionKey",
|
||||
"OutputPath",
|
||||
"Bframe",
|
||||
"MovFlags",
|
||||
}
|
||||
for _, name := range opts {
|
||||
opt := reflect.ValueOf(m).MethodByName(fmt.Sprintf("Obtain%s", name))
|
||||
@@ -604,6 +715,13 @@ func (m *Mediafile) ObtainAspect() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainHardwareAcceleration() []string {
|
||||
if m.hwaccel != "" {
|
||||
return []string{"-hwaccel", m.hwaccel}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainInputPath() []string {
|
||||
if m.inputPath != "" {
|
||||
return []string{"-i", m.inputPath}
|
||||
@@ -611,13 +729,27 @@ func (m *Mediafile) ObtainInputPath() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainInputPipeCommand() []string {
|
||||
if m.inputPipeCommand != nil {
|
||||
func (m *Mediafile) ObtainInputPipe() []string {
|
||||
if m.inputPipe {
|
||||
return []string{"-i", "pipe:0"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainOutputPipe() []string {
|
||||
if m.outputPipe {
|
||||
return []string{"pipe:1"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainMovFlags() []string {
|
||||
if m.movFlags != "" {
|
||||
return []string{"-movflags", m.movFlags}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainHideBanner() []string {
|
||||
if m.hideBanner {
|
||||
return []string{"-hide_banner"}
|
||||
@@ -633,7 +765,10 @@ func (m *Mediafile) ObtainNativeFramerateInput() []string {
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainOutputPath() []string {
|
||||
return []string{m.outputPath}
|
||||
if m.outputPath != "" {
|
||||
return []string{m.outputPath}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainVideoCodec() []string {
|
||||
@@ -672,8 +807,8 @@ func (m *Mediafile) ObtainResolution() []string {
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainVideoBitRate() []string {
|
||||
if m.videoBitRate != 0 {
|
||||
return []string{"-b:v", fmt.Sprintf("%d", m.videoBitRate)}
|
||||
if m.videoBitRate != "" {
|
||||
return []string{"-b:v", m.videoBitRate}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -734,7 +869,7 @@ func (m *Mediafile) ObtainVideoBitRateTolerance() []string {
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainThreads() []string {
|
||||
if m.threads != 0 {
|
||||
if m.threadset {
|
||||
return []string{"-threads", fmt.Sprintf("%d", m.threads)}
|
||||
}
|
||||
return nil
|
||||
@@ -796,9 +931,16 @@ func (m *Mediafile) ObtainTune() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainQuality() []string {
|
||||
if m.quality != 0 {
|
||||
return []string{"-crf", fmt.Sprintf("%d", m.quality)}
|
||||
func (m *Mediafile) ObtainCRF() []string {
|
||||
if m.crf != 0 {
|
||||
return []string{"-crf", fmt.Sprintf("%d", m.crf)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainQScale() []string {
|
||||
if m.qscale != 0 {
|
||||
return []string{"-qscale", fmt.Sprintf("%d", m.qscale)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -888,6 +1030,22 @@ func (m *Mediafile) ObtainHlsSegmentDuration() []string {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainHlsMasterPlaylistName() []string {
|
||||
if m.hlsMasterPlaylistName != "" {
|
||||
return []string{"-master_pl_name", fmt.Sprintf("%s", m.hlsMasterPlaylistName)}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainHlsSegmentFilename() []string {
|
||||
if m.hlsSegmentFilename != "" {
|
||||
return []string{"-hls_segment_filename", fmt.Sprintf("%s", m.hlsSegmentFilename)}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainHttpMethod() []string {
|
||||
if m.httpMethod != "" {
|
||||
return []string{"-method", m.httpMethod}
|
||||
@@ -938,6 +1096,21 @@ func (m *Mediafile) ObtainStreamIds() []string {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainEncryptionKey() []string {
|
||||
return []string{"-hls_key_info_file", m.encryptionKey}
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainBframe() []string {
|
||||
if m.bframe != 0 {
|
||||
return []string{"-bf", fmt.Sprintf("%d", m.bframe)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainMovFlags() []string {
|
||||
if m.movflags != "" {
|
||||
return []string{"-movflags", m.movflags}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+41
-23
@@ -1,9 +1,13 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/xfrr/goffmpeg/transcoder"
|
||||
)
|
||||
|
||||
@@ -230,29 +234,6 @@ func TestTranscodingWMV(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranscodingInputPipe(t *testing.T) {
|
||||
|
||||
// Tests pipe with input mpeg, output mp4 using cat command for pipe-in
|
||||
var outputPath = "/data/out/testmp4.mp4"
|
||||
|
||||
trans := new(transcoder.Transcoder)
|
||||
err := trans.InitializeEmptyTranscoder()
|
||||
trans.SetOutputPath(outputPath)
|
||||
trans.CreateInputPipe(exec.Command("cat", "/data/testmpeg"))
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
done := trans.Run(false)
|
||||
err = <-done
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranscodingProgress(t *testing.T) {
|
||||
|
||||
var inputPath = "/data/testavi"
|
||||
@@ -279,3 +260,40 @@ func TestTranscodingProgress(t *testing.T) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranscodePipes(t *testing.T) {
|
||||
c1 := exec.Command("cat", "/tmp/data/testmkv")
|
||||
|
||||
trans := new(transcoder.Transcoder)
|
||||
|
||||
err := trans.InitializeEmptyTranscoder()
|
||||
assert.Nil(t, err)
|
||||
|
||||
w, err := trans.CreateInputPipe()
|
||||
assert.Nil(t, err)
|
||||
c1.Stdout = w
|
||||
|
||||
r, err := trans.CreateOutputPipe("mp4")
|
||||
assert.Nil(t, err)
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
_, err := ioutil.ReadAll(r)
|
||||
assert.Nil(t, err)
|
||||
|
||||
r.Close()
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
err := c1.Run()
|
||||
assert.Nil(t, err)
|
||||
w.Close()
|
||||
}()
|
||||
done := trans.Run(false)
|
||||
err = <-done
|
||||
assert.Nil(t, err)
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
+63
-24
@@ -7,7 +7,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
@@ -103,31 +102,53 @@ func (t *Transcoder) InitializeEmptyTranscoder() error {
|
||||
|
||||
// SetInputPath sets the input path for transcoding
|
||||
func (t *Transcoder) SetInputPath(inputPath string) error {
|
||||
if t.mediafile.InputPipeCommand() != nil {
|
||||
if t.mediafile.InputPipe() {
|
||||
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")
|
||||
// SetOutputPath sets the output path for transcoding
|
||||
func (t *Transcoder) SetOutputPath(inputPath string) error {
|
||||
if t.mediafile.OutputPipe() {
|
||||
return errors.New("cannot set an input path when an input pipe command has been set")
|
||||
}
|
||||
t.mediafile.SetInputPipeCommand(cmd)
|
||||
t.mediafile.SetOutputPath(inputPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetOutputPath sets the output path for transcoding
|
||||
func (t *Transcoder) SetOutputPath(outputPath string) {
|
||||
t.mediafile.SetOutputPath(outputPath)
|
||||
// CreateInputPipe creates an input pipe for the transcoding process
|
||||
func (t *Transcoder) CreateInputPipe() (*io.PipeWriter, error) {
|
||||
if t.mediafile.InputPath() != "" {
|
||||
return nil, errors.New("cannot set an input pipe when an input path exists")
|
||||
}
|
||||
inputPipeReader, inputPipeWriter := io.Pipe()
|
||||
t.mediafile.SetInputPipe(true)
|
||||
t.mediafile.SetInputPipeReader(inputPipeReader)
|
||||
t.mediafile.SetInputPipeWriter(inputPipeWriter)
|
||||
return inputPipeWriter, nil
|
||||
}
|
||||
|
||||
// CreateOutputPipe creates an output pipe for the transcoding process
|
||||
func (t *Transcoder) CreateOutputPipe(containerFormat string) (*io.PipeReader, error) {
|
||||
if t.mediafile.OutputPath() != "" {
|
||||
return nil, errors.New("cannot set an output pipe when an output path exists")
|
||||
}
|
||||
t.mediafile.SetOutputFormat(containerFormat)
|
||||
|
||||
t.mediafile.SetMovFlags("frag_keyframe")
|
||||
outputPipeReader, outputPipeWriter := io.Pipe()
|
||||
t.mediafile.SetOutputPipe(true)
|
||||
t.mediafile.SetOutputPipeReader(outputPipeReader)
|
||||
t.mediafile.SetOutputPipeWriter(outputPipeWriter)
|
||||
return outputPipeReader, nil
|
||||
}
|
||||
|
||||
// Initialize Init the transcoding process
|
||||
func (t *Transcoder) Initialize(inputPath string, outputPath string) error {
|
||||
var err error
|
||||
var out bytes.Buffer
|
||||
var outb, errb bytes.Buffer
|
||||
var Metadata models.Metadata
|
||||
|
||||
cfg := t.configuration
|
||||
@@ -146,14 +167,15 @@ func (t *Transcoder) Initialize(inputPath string, outputPath string) error {
|
||||
command := []string{"-i", inputPath, "-print_format", "json", "-show_format", "-show_streams", "-show_error"}
|
||||
|
||||
cmd := exec.Command(cfg.FfprobeBin, command...)
|
||||
cmd.Stdout = &out
|
||||
cmd.Stdout = &outb
|
||||
cmd.Stderr = &errb
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error executing (%s) | error: %s", command, err)
|
||||
return fmt.Errorf("error executing (%s) | error: %s | message: %s %s", command, err, outb.String(), errb.String())
|
||||
}
|
||||
|
||||
if err = json.Unmarshal([]byte(out.String()), &Metadata); err != nil {
|
||||
if err = json.Unmarshal([]byte(outb.String()), &Metadata); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -190,6 +212,7 @@ func (t *Transcoder) Run(progress bool) <-chan error {
|
||||
}
|
||||
}
|
||||
|
||||
// Set the stdinPipe in case we need to stop the transcoding
|
||||
stdin, err := proc.StdinPipe()
|
||||
if nil != err {
|
||||
fmt.Println("Stdin not available: " + err.Error())
|
||||
@@ -197,23 +220,29 @@ func (t *Transcoder) Run(progress bool) <-chan error {
|
||||
|
||||
t.stdStdinPipe = stdin
|
||||
|
||||
out := &bytes.Buffer{}
|
||||
// If the user has requested progress, we send it to them on a Buffer
|
||||
var outb, errb bytes.Buffer
|
||||
if progress {
|
||||
proc.Stdout = out
|
||||
proc.Stdout = &outb
|
||||
proc.Stderr = &errb
|
||||
}
|
||||
|
||||
// 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
|
||||
// If an input pipe has been set, we set it as stdin for the transcoding
|
||||
if t.mediafile.InputPipe() {
|
||||
proc.Stdin = t.mediafile.InputPipeReader()
|
||||
}
|
||||
|
||||
// If an output pipe has been set, we set it as stdout for the transcoding
|
||||
if t.mediafile.OutputPipe() {
|
||||
proc.Stdout = t.mediafile.OutputPipeWriter()
|
||||
}
|
||||
|
||||
err = proc.Start()
|
||||
|
||||
t.SetProcess(proc)
|
||||
go func(err error, out *bytes.Buffer) {
|
||||
go func(err error) {
|
||||
if err != nil {
|
||||
done <- fmt.Errorf("Failed Start FFMPEG (%s) with %s, message %s", command, err, out.String())
|
||||
done <- fmt.Errorf("Failed Start FFMPEG (%s) with %s, message %s %s", command, err, outb.String(), errb.String())
|
||||
close(done)
|
||||
return
|
||||
}
|
||||
@@ -228,12 +257,13 @@ func (t *Transcoder) Run(progress bool) <-chan error {
|
||||
}
|
||||
|
||||
err = proc.Wait()
|
||||
go t.closePipes()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Failed Finish FFMPEG (%s) with %s message %s", command, err, out.String())
|
||||
err = fmt.Errorf("Failed Finish FFMPEG (%s) with %s message %s %s", command, err, outb.String(), errb.String())
|
||||
}
|
||||
done <- err
|
||||
close(done)
|
||||
}(err, out)
|
||||
}(err)
|
||||
|
||||
return done
|
||||
}
|
||||
@@ -345,3 +375,12 @@ func (t Transcoder) Output() <-chan models.Progress {
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (t *Transcoder) closePipes() {
|
||||
if t.mediafile.InputPipe() {
|
||||
t.mediafile.InputPipeReader().Close()
|
||||
}
|
||||
if t.mediafile.OutputPipe() {
|
||||
t.mediafile.OutputPipeWriter().Close()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user