Fixing execution model and making compatible with windows

This commit is contained in:
Rohit Garg
2018-06-26 19:29:50 +05:30
parent 53621db373
commit 25818c560b
7 changed files with 296 additions and 395 deletions

View File

@@ -39,10 +39,11 @@ func main() {
// Handle error... // Handle error...
// Start transcoder process // Start transcoder process
done, err := trans.Run() done := trans.Run()
// This channel is used to wait for the process to end // This channel is used to wait for the process to end
<-done err = <-done
// Handle error...
} }
``` ```
@@ -59,10 +60,10 @@ func main() {
// Handle error... // Handle error...
// Start transcoder process // Start transcoder process
done, err := trans.Run() done := trans.Run()
// Returns a channel to get the transcoding progress // Returns a channel to get the transcoding progress
progress, err := trans.Output() progress := trans.Output()
// Example of printing transcoding progress // Example of printing transcoding progress
for msg := range progress { for msg := range progress {
@@ -70,7 +71,7 @@ func main() {
} }
// This channel is used to wait for the transcoding process to end // This channel is used to wait for the transcoding process to end
<-done err = <-done
} }
``` ```
@@ -139,10 +140,10 @@ func main() {
trans.MediaFile().SetPreset("ultrafast") trans.MediaFile().SetPreset("ultrafast")
// Start transcoder process // Start transcoder process
done, err := trans.Run() done := trans.Run()
// Returns a channel to get the transcoding progress // Returns a channel to get the transcoding progress
progress, err := trans.Output() progress := trans.Output()
// Example of printing transcoding progress // Example of printing transcoding progress
for msg := range progress { for msg := range progress {
@@ -150,7 +151,7 @@ func main() {
} }
// This channel is used to wait for the transcoding process to end // This channel is used to wait for the transcoding process to end
<-done err = <-done
} }
``` ```

View File

@@ -10,49 +10,33 @@ import (
type Configuration struct { type Configuration struct {
FfmpegBin string FfmpegBin string
FfprobeBin string FfprobeBin string
ExecCmd string
ExecArgs string
} }
func Configure() (Configuration, error) { func Configure() (Configuration, error) {
var outFFmpeg bytes.Buffer var outFFmpeg bytes.Buffer
var outProbe bytes.Buffer var outProbe bytes.Buffer
execCmd := utils.GetExec()
execFFmpegCommand := utils.GetFFmpegExec() execFFmpegCommand := utils.GetFFmpegExec()
execFFprobeCommand := utils.GetFFprobeExec() execFFprobeCommand := utils.GetFFprobeExec()
execArgs := utils.GetExecArgs()
cmdFFmpeg := exec.Command(execCmd, execArgs, execFFmpegCommand) cmdFFmpeg := exec.Command(execFFmpegCommand[0], execFFmpegCommand[1])
cmdProbe := exec.Command(execCmd, execArgs, execFFprobeCommand) cmdProbe := exec.Command(execFFprobeCommand[0], execFFprobeCommand[1])
cmdFFmpeg.Stdout = &outFFmpeg cmdFFmpeg.Stdout = &outFFmpeg
cmdProbe.Stdout = &outProbe cmdProbe.Stdout = &outProbe
err := cmdFFmpeg.Start() err := cmdFFmpeg.Run()
if err != nil { if err != nil {
return Configuration{}, err return Configuration{}, err
} }
_, err = cmdFFmpeg.Process.Wait() err = cmdProbe.Run()
if err != nil { if err != nil {
return Configuration{}, err return Configuration{}, err
} }
err = cmdProbe.Start() ffmpeg := strings.Replace(outFFmpeg.String(), utils.LineSeparator(), "", -1)
if err != nil { fprobe := strings.Replace(outProbe.String(), utils.LineSeparator(), "", -1)
return Configuration{}, err
}
_, err = cmdProbe.Process.Wait()
if err != nil {
return Configuration{}, err
}
ffmpeg := strings.Replace(outFFmpeg.String(), "\n", "", -1)
fprobe := strings.Replace(outProbe.String(), "\n", "", -1)
cnf := Configuration{ffmpeg, fprobe, execCmd, execArgs}
cnf := Configuration{ffmpeg, fprobe}
return cnf, nil return cnf, nil
} }

View File

@@ -362,10 +362,10 @@ func (m *Mediafile) Metadata() Metadata {
} }
/** OPTS **/ /** OPTS **/
func (m *Mediafile) ToStrCommand() string { func (m *Mediafile) ToStrCommand() []string {
var strCommand string var strCommand []string
opts := [] string { opts := []string {
"SeekTimeInput", "SeekTimeInput",
"SeekUsingTsInput", "SeekUsingTsInput",
"NativeFramerateInput", "NativeFramerateInput",
@@ -409,278 +409,276 @@ func (m *Mediafile) ToStrCommand() string {
if (opt != reflect.Value{}) { if (opt != reflect.Value{}) {
result := opt.Call([]reflect.Value{}) result := opt.Call([]reflect.Value{})
if result[0].String() != "" { if val, ok := result[0].Interface().([]string); ok {
strCommand += " " strCommand = append(strCommand, val...)
strCommand += result[0].String()
} }
} }
} }
return strCommand return strCommand
} }
func (m *Mediafile) ObtainAspect() string { func (m *Mediafile) ObtainAspect() []string {
// Set aspect // Set aspect
if m.resolution != "" { if m.resolution != "" {
resolution := strings.Split(m.resolution, "x") resolution := strings.Split(m.resolution, "x")
if len(resolution) != 0 { if len(resolution) != 0 {
width, _ := strconv.ParseFloat(resolution[0], 64) width, _ := strconv.ParseFloat(resolution[0], 64)
height, _ := strconv.ParseFloat(resolution[1], 64) height, _ := strconv.ParseFloat(resolution[1], 64)
return fmt.Sprintf("-aspect %f", width/height) return []string{"-aspect", fmt.Sprintf("%f", width/height)}
} }
} }
if m.aspect != "" { if m.aspect != "" {
return fmt.Sprintf("-aspect %s", m.aspect) return []string{"-aspect", m.aspect}
} }
return "" return nil
} }
func (m *Mediafile) ObtainInputPath() string { func (m *Mediafile) ObtainInputPath() []string {
return fmt.Sprintf("-i \"%s\"", m.inputPath) return []string{"-i", m.inputPath}
} }
func (m *Mediafile) ObtainNativeFramerateInput() string { func (m *Mediafile) ObtainNativeFramerateInput() []string {
if m.nativeFramerateInput { if m.nativeFramerateInput {
return "-re" return []string{"-re"}
} }
return "" return nil
} }
func (m *Mediafile) ObtainOutputPath() string { func (m *Mediafile) ObtainOutputPath() []string {
return fmt.Sprintf("\"%s\"", m.outputPath) return []string{m.outputPath}
} }
func (m *Mediafile) ObtainVideoCodec() string { func (m *Mediafile) ObtainVideoCodec() []string {
if m.videoCodec != "" { if m.videoCodec != "" {
return fmt.Sprintf("-c:v %s", m.videoCodec) return []string{"-c:v", m.videoCodec}
} }
return "" return nil
} }
func (m *Mediafile) ObtainFrameRate() string { func (m *Mediafile) ObtainFrameRate() []string {
if m.frameRate != 0 { if m.frameRate != 0 {
return fmt.Sprintf("-r %d", m.frameRate) return []string{"-r",fmt.Sprintf("%d", m.frameRate)}
} }
return "" return nil
} }
func (m *Mediafile) ObtainResolution() string { func (m *Mediafile) ObtainResolution() []string {
if m.resolution != "" { if m.resolution != "" {
return fmt.Sprintf("-s %s", m.resolution) return []string{"-s", m.resolution}
} }
return "" return nil
} }
func (m *Mediafile) ObtainVideoBitRate() string { func (m *Mediafile) ObtainVideoBitRate() []string {
if m.videoBitRate != 0 { if m.videoBitRate != 0 {
return fmt.Sprintf("-b:v %d", m.videoBitRate) return []string{"-b:v", fmt.Sprintf("%d", m.videoBitRate)}
} }
return "" return nil
} }
func (m *Mediafile) ObtainAudioCodec() string { func (m *Mediafile) ObtainAudioCodec() []string {
if m.audioCodec != "" { if m.audioCodec != "" {
return fmt.Sprintf("-c:a %s", m.audioCodec) return []string{"-c:a", m.audioCodec}
} }
return "" return nil
} }
func (m *Mediafile) ObtainAudioBitRate() string { func (m *Mediafile) ObtainAudioBitRate() []string {
if m.audioBitrate != 0 { if m.audioBitrate != 0 {
return fmt.Sprintf("-b:a %d", m.audioBitrate) return []string{"-b:a", fmt.Sprintf("%d", m.audioBitrate)}
} }
return "" return nil
} }
func (m *Mediafile) ObtainAudioChannels() string { func (m *Mediafile) ObtainAudioChannels() []string {
if m.audioChannels != 0 { if m.audioChannels != 0 {
return fmt.Sprintf("-ac %d", m.audioChannels) return []string{"-ac",fmt.Sprintf("%d", m.audioChannels)}
} }
return "" return nil
} }
func (m *Mediafile) ObtainVideoMaxBitRate() string { func (m *Mediafile) ObtainVideoMaxBitRate() []string {
if m.videoMaxBitRate != 0 { if m.videoMaxBitRate != 0 {
return fmt.Sprintf("-maxrate %dk", m.videoMaxBitRate) return []string{"-maxrate",fmt.Sprintf("%dk", m.videoMaxBitRate)}
} }
return "" return nil
} }
func (m *Mediafile) ObtainVideoMinBitRate() string { func (m *Mediafile) ObtainVideoMinBitRate() []string {
if m.videoMinBitrate != 0 { if m.videoMinBitrate != 0 {
return fmt.Sprintf("-minrate %dk", m.videoMinBitrate) return []string{"-minrate",fmt.Sprintf("%dk", m.videoMinBitrate)}
} }
return "" return nil
} }
func (m *Mediafile) ObtainBufferSize() string { func (m *Mediafile) ObtainBufferSize() []string {
if m.bufferSize != 0 { if m.bufferSize != 0 {
return fmt.Sprintf("-bufsize %dk", m.bufferSize) return []string{"-bufsize",fmt.Sprintf("%dk", m.bufferSize)}
} }
return "" return nil
} }
func (m *Mediafile) ObtainVideoBitRateTolerance() string { func (m *Mediafile) ObtainVideoBitRateTolerance() []string {
if m.videoBitRateTolerance != 0 { if m.videoBitRateTolerance != 0 {
return fmt.Sprintf("-bt %dk", m.videoBitRateTolerance) return []string{"-bt",fmt.Sprintf("%dk", m.videoBitRateTolerance)}
} }
return "" return nil
} }
func (m *Mediafile) ObtainThreads() string { func (m *Mediafile) ObtainThreads() []string {
if m.threads != 0 { if m.threads != 0 {
return fmt.Sprintf("-threads %d", m.threads) return []string{"-threads",fmt.Sprintf("%d", m.threads)}
} }
return "" return nil
} }
func (m *Mediafile) ObtainTarget() string { func (m *Mediafile) ObtainTarget() []string {
if m.target != "" { if m.target != "" {
return fmt.Sprintf("-target %s", m.target) return []string{"-target",m.target}
} }
return "" return nil
} }
func (m *Mediafile) ObtainDuration() string { func (m *Mediafile) ObtainDuration() []string {
if m.duration != "" { if m.duration != "" {
return fmt.Sprintf("-t %s", m.duration) return []string{"-t",m.duration}
} }
return "" return nil
} }
func (m *Mediafile) ObtainDurationInput() string { func (m *Mediafile) ObtainDurationInput() []string {
if m.durationInput != "" { if m.durationInput != "" {
return fmt.Sprintf("-t %s", m.durationInput) return []string{"-t",m.durationInput}
} }
return "" return nil
} }
func (m *Mediafile) ObtainKeyframeInterval() string { func (m *Mediafile) ObtainKeyframeInterval() []string {
if m.keyframeInterval != 0 { if m.keyframeInterval != 0 {
return fmt.Sprintf("-g %d", m.keyframeInterval) return []string{"-g",fmt.Sprintf("%d", m.keyframeInterval)}
} }
return "" return nil
} }
func (m *Mediafile) ObtainSeekTime() string { func (m *Mediafile) ObtainSeekTime() []string {
if m.seekTime != "" { if m.seekTime != "" {
return fmt.Sprintf("-ss %s", m.seekTime) return []string{"-ss",m.seekTime}
} }
return "" return nil
} }
func (m *Mediafile) ObtainSeekTimeInput() string { func (m *Mediafile) ObtainSeekTimeInput() []string {
if m.seekTimeInput != "" { if m.seekTimeInput != "" {
return fmt.Sprintf("-ss %s", m.seekTimeInput) return []string{"-ss",m.seekTimeInput}
} }
return "" return nil
} }
func (m *Mediafile) ObtainPreset() string { func (m *Mediafile) ObtainPreset() []string {
if m.preset != "" { if m.preset != "" {
return fmt.Sprintf("-preset %s", m.preset) return []string{"-preset",m.preset}
} }
return "" return nil
} }
func (m *Mediafile) ObtainTune() string { func (m *Mediafile) ObtainTune() []string {
if m.tune != "" { if m.tune != "" {
return fmt.Sprintf("-tune %s", m.tune) return []string{"-tune",m.tune}
} }
return "" return nil
} }
func (m *Mediafile) ObtainQuality() string { func (m *Mediafile) ObtainQuality() []string {
if m.quality != 0 { if m.quality != 0 {
return fmt.Sprintf("-crf %d", m.quality) return []string{"-crf",fmt.Sprintf("%d", m.quality)}
} }
return "" return nil
} }
func (m *Mediafile) ObtainVideoProfile() string { func (m *Mediafile) ObtainVideoProfile() []string {
if m.videoProfile != "" { if m.videoProfile != "" {
return fmt.Sprintf("-profile:v %s", m.videoProfile) return []string{"-profile:v",m.videoProfile}
} }
return "" return nil
} }
func (m *Mediafile) ObtainAudioProfile() string { func (m *Mediafile) ObtainAudioProfile() []string {
if m.audioProfile != "" { if m.audioProfile != "" {
return fmt.Sprintf("-profile:a %s", m.audioProfile) return []string{"-profile:a", m.audioProfile}
} }
return "" return nil
} }
func (m *Mediafile) ObtainCopyTs() string { func (m *Mediafile) ObtainCopyTs() []string {
if m.copyTs { if m.copyTs {
return "-copyts" return []string{"-copyts"}
} }
return "" return nil
} }
func (m *Mediafile) ObtainOutputFormat() string { func (m *Mediafile) ObtainOutputFormat() []string {
if m.outputFormat != "" { if m.outputFormat != "" {
return fmt.Sprintf("-f %s", m.outputFormat) return []string{"-f",m.outputFormat}
} }
return "" return nil
} }
func (m *Mediafile) ObtainMuxDelay() string { func (m *Mediafile) ObtainMuxDelay() []string {
if m.muxDelay != "" { if m.muxDelay != "" {
return fmt.Sprintf("-muxdelay %s", m.muxDelay) return []string{"-muxdelay",m.muxDelay}
} }
return "" return nil
} }
func (m *Mediafile) ObtainSeekUsingTsInput() string { func (m *Mediafile) ObtainSeekUsingTsInput() []string {
if m.seekUsingTsInput { if m.seekUsingTsInput {
return "-seek_timestamp 1" return []string{"-seek_timestamp", "1"}
} }
return "" return nil
} }
func (m *Mediafile) ObtainRtmpLive() string { func (m *Mediafile) ObtainRtmpLive() []string {
if m.rtmpLive != "" { if m.rtmpLive != "" {
return fmt.Sprintf("-rtmp_live %s", m.rtmpLive) return []string{"-rtmp_live",m.rtmpLive}
} else { } else {
return "" return nil
} }
} }
func (m *Mediafile) ObtainHlsPlaylistType() string { func (m *Mediafile) ObtainHlsPlaylistType() []string {
if m.hlsPlaylistType != "" { if m.hlsPlaylistType != "" {
return fmt.Sprintf("-hls_playlist_type %s", m.hlsPlaylistType) return []string{"-hls_playlist_type",m.hlsPlaylistType}
} else { } else {
return "" return nil
} }
} }
func (m *Mediafile) ObtainInputInitialOffset() string { func (m *Mediafile) ObtainInputInitialOffset() []string {
if m.inputInitialOffset != "" { if m.inputInitialOffset != "" {
return fmt.Sprintf("-itsoffset %s", m.inputInitialOffset) return []string{"-itsoffset",m.inputInitialOffset}
} else { } else {
return "" return nil
} }
} }
func (m *Mediafile) ObtainHlsSegmentDuration() string { func (m *Mediafile) ObtainHlsSegmentDuration() []string {
if m.hlsSegmentDuration != 0 { if m.hlsSegmentDuration != 0 {
return fmt.Sprintf("-hls_time %d", m.hlsSegmentDuration) return []string{"-hls_time",fmt.Sprintf("%d", m.hlsSegmentDuration)}
} else { } else {
return "" return nil
} }
} }
func (m *Mediafile) ObtainStreamIds() string { func (m *Mediafile) ObtainStreamIds() []string {
if m.streamIds != nil && len(m.streamIds) != 0 { if m.streamIds != nil && len(m.streamIds) != 0 {
result := []string{} result := []string{}
for i, val := range m.streamIds { for i, val := range m.streamIds {
result = append(result, fmt.Sprintf("-streamid %d:%s", i, val)) result = append(result, []string{"-streamid", fmt.Sprintf("%d:%s", i, val)}...)
} }
return strings.Join(result, " ") return result
} }
return "" return nil
} }

View File

@@ -2,7 +2,7 @@ package test
import ( import (
"testing" "testing"
"goffmpeg/transcoder" "github.com/xfrr/goffmpeg/transcoder"
) )
func TestInputNotFound(t *testing.T) { func TestInputNotFound(t *testing.T) {
@@ -31,13 +31,12 @@ func TestTranscoding3GP(t *testing.T) {
return return
} }
done, err := trans.Run() done := trans.Run()
err = <- done
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
<-done
} }
func TestTranscodingAVI(t *testing.T) { func TestTranscodingAVI(t *testing.T) {
@@ -53,13 +52,12 @@ func TestTranscodingAVI(t *testing.T) {
return return
} }
done, err := trans.Run() done := trans.Run()
err = <- done
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
<-done
} }
func TestTranscodingFLV(t *testing.T) { func TestTranscodingFLV(t *testing.T) {
@@ -75,13 +73,12 @@ func TestTranscodingFLV(t *testing.T) {
return return
} }
done, err := trans.Run() done := trans.Run()
err = <- done
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
<-done
} }
func TestTranscodingMKV(t *testing.T) { func TestTranscodingMKV(t *testing.T) {
@@ -97,13 +94,12 @@ func TestTranscodingMKV(t *testing.T) {
return return
} }
done, err := trans.Run() done := trans.Run()
err = <-done
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
<-done
} }
func TestTranscodingMOV(t *testing.T) { func TestTranscodingMOV(t *testing.T) {
@@ -119,13 +115,12 @@ func TestTranscodingMOV(t *testing.T) {
return return
} }
done, err := trans.Run() done := trans.Run()
err = <-done
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
<-done
} }
func TestTranscodingMPEG(t *testing.T) { func TestTranscodingMPEG(t *testing.T) {
@@ -141,13 +136,12 @@ func TestTranscodingMPEG(t *testing.T) {
return return
} }
done, err := trans.Run() done := trans.Run()
err = <-done
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
<-done
} }
func TestTranscodingOGG(t *testing.T) { func TestTranscodingOGG(t *testing.T) {
@@ -163,13 +157,12 @@ func TestTranscodingOGG(t *testing.T) {
return return
} }
done, err := trans.Run() done := trans.Run()
err = <- done
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
<-done
} }
func TestTranscodingWAV(t *testing.T) { func TestTranscodingWAV(t *testing.T) {
@@ -185,13 +178,12 @@ func TestTranscodingWAV(t *testing.T) {
return return
} }
done, err := trans.Run() done := trans.Run()
err = <- done
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
<-done
} }
func TestTranscodingWEBM(t *testing.T) { func TestTranscodingWEBM(t *testing.T) {
@@ -207,13 +199,12 @@ func TestTranscodingWEBM(t *testing.T) {
return return
} }
done, err := trans.Run() done := trans.Run()
err = <- done
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
<-done
} }
func TestTranscodingWMV(t *testing.T) { func TestTranscodingWMV(t *testing.T) {
@@ -229,11 +220,10 @@ func TestTranscodingWMV(t *testing.T) {
return return
} }
done, err := trans.Run() done := trans.Run()
err = <- done
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
<-done
} }

View File

@@ -1,29 +0,0 @@
package transcoder
import (
"fmt"
"log"
"os/exec"
)
type Worker struct {
Command string
Args string
Output chan string
}
func (cmd *Worker) Run() {
out, err := exec.Command(cmd.Command, cmd.Args).Output()
if err != nil {
log.Fatal(err)
}
cmd.Output <- string(out)
}
func Collect(c chan string) {
for {
msg := <-c
fmt.Printf("The command result is %s\n", msg)
}
}

View File

@@ -14,16 +14,17 @@ import (
"strings" "strings"
"regexp" "regexp"
"strconv" "strconv"
"io"
) )
type Transcoder struct { type Transcoder struct {
process *exec.Cmd stdErrPipe io.ReadCloser
mediafile *models.Mediafile mediafile *models.Mediafile
configuration ffmpeg.Configuration configuration ffmpeg.Configuration
} }
func (t *Transcoder) SetProccess(v *exec.Cmd) { func (t *Transcoder) SetProcessStderrPipe(v io.ReadCloser) {
t.process = v t.stdErrPipe = v
} }
func (t *Transcoder) SetMediaFile(v *models.Mediafile) { func (t *Transcoder) SetMediaFile(v *models.Mediafile) {
@@ -36,10 +37,6 @@ func (t *Transcoder) SetConfiguration(v ffmpeg.Configuration) {
/*** GETTERS ***/ /*** GETTERS ***/
func (t Transcoder) Process() *exec.Cmd {
return t.process
}
func (t Transcoder) MediaFile() *models.Mediafile { func (t Transcoder) MediaFile() *models.Mediafile {
return t.mediafile return t.mediafile
} }
@@ -52,17 +49,10 @@ func (t Transcoder) FFprobeExec() string {
return t.configuration.FfprobeBin return t.configuration.FfprobeBin
} }
func (t Transcoder) GetCommand() string { func (t Transcoder) GetCommand() []string {
var rcommand string
rcommand = fmt.Sprintf("%s -y ", t.configuration.FfmpegBin)
media := t.mediafile media := t.mediafile
rcommand := append([]string{"-y"}, media.ToStrCommand()...)
rcommand += media.ToStrCommand()
return rcommand return rcommand
} }
/*** FUNCTIONS ***/ /*** FUNCTIONS ***/
@@ -84,25 +74,16 @@ func (t *Transcoder) Initialize(inputPath string, outputPath string) (error) {
return errors.New("error: transcoder.Initialize -> input file not found") return errors.New("error: transcoder.Initialize -> input file not found")
} }
command := fmt.Sprintf("%s -i \"%s\" -print_format json -show_format -show_streams -show_error", configuration.FfprobeBin, inputPath) command := []string{"-i", inputPath, "-print_format", "json", "-show_format", "-show_streams", "-show_error"}
cmd := exec.Command(configuration.ExecCmd, configuration.ExecArgs, command) cmd := exec.Command(configuration.FfprobeBin, command...)
fmt.Println("FFprobe command: " + command)
var out bytes.Buffer var out bytes.Buffer
cmd.Stdout = &out cmd.Stdout = &out
err = cmd.Start() err = cmd.Run()
if err != nil { if err != nil {
return err return fmt.Errorf("Failed FFPROBE (%s) with %s, message %s", command, err, out.String())
}
_, err = cmd.Process.Wait()
if err != nil {
return err
} }
var Metadata models.Metadata var Metadata models.Metadata
@@ -112,151 +93,154 @@ func (t *Transcoder) Initialize(inputPath string, outputPath string) (error) {
} }
// Set new Mediafile // Set new Mediafile
MediaFile := new(models.Mediafile) MediaFile := new(models.Mediafile)
MediaFile.SetMetadata(Metadata) MediaFile.SetMetadata(Metadata)
MediaFile.SetInputPath(inputPath) MediaFile.SetInputPath(inputPath)
MediaFile.SetOutputPath(outputPath) MediaFile.SetOutputPath(outputPath)
// Set transcoder configuration // Set transcoder configuration
t.SetMediaFile(MediaFile) t.SetMediaFile(MediaFile)
t.SetConfiguration(configuration) t.SetConfiguration(configuration)
return nil return nil
} }
func (t *Transcoder) Run() (<-chan bool, error) { func (t *Transcoder) Run() <-chan error {
done := make(chan bool) done := make(chan error)
var err error
command := t.GetCommand() command := t.GetCommand()
fmt.Println("FFmpeg command: " + command) proc := exec.Command(t.configuration.FfmpegBin, command...)
proc := exec.Command(t.configuration.ExecCmd, t.configuration.ExecArgs, command) errStream, err := proc.StderrPipe()
if err != nil {
fmt.Println("Progress not available: "+ err.Error())
} else {
t.SetProcessStderrPipe(errStream)
}
t.SetProccess(proc) out := &bytes.Buffer{}
proc.Stdout = out
go func() { err = proc.Start()
err := proc.Start()
go func(err error, out *bytes.Buffer, errStream io.ReadCloser) {
defer func() {
if errStream != nil {
errStream.Close()
}
}()
if err != nil { if err != nil {
done <- fmt.Errorf("Failed Start FFMPEG (%s) with %s, message %s", command, err, out.String())
close(done)
return return
} }
err = proc.Wait()
proc.Wait() if err != nil {
err = fmt.Errorf("Failed Finish FFMPEG (%s) with %s message %s", command, err, out.String())
done <- true }
done <- err
close(done) close(done)
}() }(err, out, errStream)
return done, err
return done
} }
func (t Transcoder) Output() (<-chan models.Progress, error) { func (t Transcoder) Output() <-chan models.Progress {
out := make(chan models.Progress) out := make(chan models.Progress)
var err error
go func() { go func() {
defer close(out) defer close(out)
if t.stdErrPipe == nil {
return
}
scanner := bufio.NewScanner(t.stdErrPipe)
filetype := utils.CheckFileType(t.MediaFile().Metadata().Streams)
stderr, stderror := t.Process().StderrPipe() split := func(data []byte, atEOF bool) (advance int, token []byte, spliterror error) {
if err != nil {
err = stderror
return
}
scanner := bufio.NewScanner(stderr)
filetype := utils.CheckFileType(t.MediaFile().Metadata().Streams)
split := func(data []byte, atEOF bool) (advance int, token []byte, spliterror error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
Iframe := strings.Index(string(data), "frame=")
if filetype == "video" {
if Iframe > 0 {
return Iframe + 1, data[Iframe:], nil
}
} else {
if i := bytes.IndexByte(data, '\n'); i >= 0 {
// We have a full newline-terminated line.
return i + 1, data[0:i], nil
}
}
if atEOF {
return len(data), data, nil
}
if atEOF && len(data) == 0 {
return 0, nil, nil return 0, nil, nil
} }
scanner.Split(split) Iframe := strings.Index(string(data), "frame=")
buf := make([]byte, 2)
scanner.Buffer(buf, bufio.MaxScanTokenSize)
var lastProgress float64 if filetype == "video" {
for scanner.Scan() { if Iframe > 0 {
Progress := new(models.Progress) return Iframe + 1, data[Iframe:], nil
line := scanner.Text() }
} else {
if strings.Contains(line, "time=") && strings.Contains(line, "bitrate=") { if i := bytes.IndexByte(data, '\n'); i >= 0 {
var re= regexp.MustCompile(`=\s+`) // We have a full newline-terminated line.
st := re.ReplaceAllString(line, `=`) return i + 1, data[0:i], nil
f := strings.Fields(st)
var framesProcessed string
var currentTime string
var currentBitrate string
for j := 0; j < len(f); j++ {
field := f[j]
fieldSplit := strings.Split(field, "=")
if len(fieldSplit) > 1 {
fieldname := strings.Split(field, "=")[0]
fieldvalue := strings.Split(field, "=")[1]
if fieldname == "frame" {
framesProcessed = fieldvalue
}
if fieldname == "time" {
currentTime = fieldvalue
}
if fieldname == "bitrate" {
currentBitrate = fieldvalue
}
}
}
timesec := utils.DurToSec(currentTime)
dursec, _ := strconv.ParseFloat(t.MediaFile().Metadata().Format.Duration, 64)
// Progress calculation
progress := (timesec * 100) / dursec
Progress.Progress = progress
Progress.CurrentBitrate = currentBitrate
Progress.FramesProcessed = framesProcessed
Progress.CurrentTime = currentTime
if progress != lastProgress {
lastProgress = progress
out <- *Progress
}
} }
} }
if scerror := scanner.Err(); err != nil { if atEOF {
err = scerror return len(data), data, nil
} }
}()
return out, err return 0, nil, nil
}
scanner.Split(split)
buf := make([]byte, 2)
scanner.Buffer(buf, bufio.MaxScanTokenSize)
var lastProgress float64
for scanner.Scan() {
Progress := new(models.Progress)
line := scanner.Text()
// fmt.Println(line)
if strings.Contains(line, "time=") && strings.Contains(line, "bitrate=") {
var re= regexp.MustCompile(`=\s+`)
st := re.ReplaceAllString(line, `=`)
f := strings.Fields(st)
var framesProcessed string
var currentTime string
var currentBitrate string
for j := 0; j < len(f); j++ {
field := f[j]
fieldSplit := strings.Split(field, "=")
if len(fieldSplit) > 1 {
fieldname := strings.Split(field, "=")[0]
fieldvalue := strings.Split(field, "=")[1]
if fieldname == "frame" {
framesProcessed = fieldvalue
}
if fieldname == "time" {
currentTime = fieldvalue
}
if fieldname == "bitrate" {
currentBitrate = fieldvalue
}
}
}
timesec := utils.DurToSec(currentTime)
dursec, _ := strconv.ParseFloat(t.MediaFile().Metadata().Format.Duration, 64)
// Progress calculation
progress := (timesec * 100) / dursec
Progress.Progress = progress
Progress.CurrentBitrate = currentBitrate
Progress.FramesProcessed = framesProcessed
Progress.CurrentTime = currentTime
if progress != lastProgress {
lastProgress = progress
out <- *Progress
}
}
}
}()
return out
} }

View File

@@ -22,67 +22,34 @@ func DurToSec(dur string) (sec float64) {
return secs return secs
} }
func GetExec() string { func GetFFmpegExec() []string {
var platform = runtime.GOOS var platform = runtime.GOOS
var command = "" var command = []string{"", "ffmpeg"}
switch platform { switch platform {
case "windows": case "windows":
command = "cmd" command[0] = "where"
break break
default: default:
command = "/bin/sh" command[0] = "which"
break break
} }
return command return command
} }
func GetExecArgs() string { func GetFFprobeExec() []string {
var platform = runtime.GOOS var platform = runtime.GOOS
var args = "" var command = []string{"", "ffprobe"}
switch platform { switch platform {
case "windows": case "windows":
args = "/C" command[0] = "where"
break break
default: default:
args = "-c" command[0] = "which"
break break
} }
return args
}
func GetFFmpegExec() string {
var platform = runtime.GOOS
var command = ""
switch platform {
case "windows":
command = "where ffmpeg"
break
default:
command = "which ffmpeg"
break
}
return command
}
func GetFFprobeExec() string {
var platform = runtime.GOOS
var command = ""
switch platform {
case "windows":
command = "where ffprobe"
break
default:
command = "which ffprobe"
break
}
return command return command
} }
@@ -98,5 +65,11 @@ func CheckFileType(streams []models.Streams) string {
return "audio" return "audio"
} }
func LineSeparator() string {
switch runtime.GOOS {
case "windows":
return "\r\n"
default:
return "\n"
}
}