mirror of
https://github.com/xfrr/goffmpeg.git
synced 2025-10-06 00:16:50 +08:00
Added progress check flag, only open stderr if progress required
This commit is contained in:
@@ -78,10 +78,11 @@ func main() {
|
|||||||
# Progress properties
|
# Progress properties
|
||||||
```golang
|
```golang
|
||||||
type Progress struct {
|
type Progress struct {
|
||||||
FramesProcessed string
|
FramesProcessed string
|
||||||
CurrentTime string
|
CurrentTime string
|
||||||
CurrentBitrate string
|
CurrentBitrate string
|
||||||
Progress float64
|
Progress float64
|
||||||
|
Speed string
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
# Media setters
|
# Media setters
|
||||||
|
@@ -73,6 +73,7 @@ type Progress struct {
|
|||||||
CurrentTime string
|
CurrentTime string
|
||||||
CurrentBitrate string
|
CurrentBitrate string
|
||||||
Progress float64
|
Progress float64
|
||||||
|
Speed string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tags struct {
|
type Tags struct {
|
||||||
|
@@ -31,7 +31,7 @@ func TestTranscoding3GP(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
done := trans.Run()
|
done := trans.Run(false)
|
||||||
err = <- done
|
err = <- done
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -52,7 +52,7 @@ func TestTranscodingAVI(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
done := trans.Run()
|
done := trans.Run(false)
|
||||||
err = <- done
|
err = <- done
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -73,7 +73,7 @@ func TestTranscodingFLV(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
done := trans.Run()
|
done := trans.Run(false)
|
||||||
err = <- done
|
err = <- done
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -94,7 +94,7 @@ func TestTranscodingMKV(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
done := trans.Run()
|
done := trans.Run(false)
|
||||||
err = <-done
|
err = <-done
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -115,7 +115,7 @@ func TestTranscodingMOV(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
done := trans.Run()
|
done := trans.Run(false)
|
||||||
err = <-done
|
err = <-done
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -136,7 +136,7 @@ func TestTranscodingMPEG(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
done := trans.Run()
|
done := trans.Run(false)
|
||||||
err = <-done
|
err = <-done
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -157,7 +157,7 @@ func TestTranscodingOGG(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
done := trans.Run()
|
done := trans.Run(false)
|
||||||
err = <- done
|
err = <- done
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -178,7 +178,7 @@ func TestTranscodingWAV(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
done := trans.Run()
|
done := trans.Run(false)
|
||||||
err = <- done
|
err = <- done
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -199,7 +199,7 @@ func TestTranscodingWEBM(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
done := trans.Run()
|
done := trans.Run(false)
|
||||||
err = <- done
|
err = <- done
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -220,7 +220,7 @@ func TestTranscodingWMV(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
done := trans.Run()
|
done := trans.Run(false)
|
||||||
err = <- done
|
err = <- done
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@@ -114,30 +114,26 @@ func (t *Transcoder) Initialize(inputPath string, outputPath string) (error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transcoder) Run() <-chan error {
|
func (t *Transcoder) Run(progress bool) <-chan error {
|
||||||
done := make(chan error)
|
done := make(chan error)
|
||||||
command := t.GetCommand()
|
command := t.GetCommand()
|
||||||
|
|
||||||
proc := exec.Command(t.configuration.FfmpegBin, command...)
|
proc := exec.Command(t.configuration.FfmpegBin, command...)
|
||||||
|
if progress {
|
||||||
errStream, err := proc.StderrPipe()
|
errStream, err := proc.StderrPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Progress not available: "+ err.Error())
|
fmt.Println("Progress not available: "+ err.Error())
|
||||||
} else {
|
} else {
|
||||||
t.SetProcessStderrPipe(errStream)
|
t.SetProcessStderrPipe(errStream)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out := &bytes.Buffer{}
|
out := &bytes.Buffer{}
|
||||||
proc.Stdout = out
|
proc.Stdout = out
|
||||||
|
|
||||||
err = proc.Start()
|
err := proc.Start()
|
||||||
t.SetProcess(proc)
|
t.SetProcess(proc)
|
||||||
go func(err error, out *bytes.Buffer, errStream io.ReadCloser) {
|
go func(err error, out *bytes.Buffer) {
|
||||||
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())
|
done <- fmt.Errorf("Failed Start FFMPEG (%s) with %s, message %s", command, err, out.String())
|
||||||
close(done)
|
close(done)
|
||||||
@@ -149,7 +145,7 @@ func (t *Transcoder) Run() <-chan error {
|
|||||||
}
|
}
|
||||||
done <- err
|
done <- err
|
||||||
close(done)
|
close(done)
|
||||||
}(err, out, errStream)
|
}(err, out)
|
||||||
|
|
||||||
return done
|
return done
|
||||||
}
|
}
|
||||||
@@ -160,30 +156,25 @@ func (t Transcoder) Output() <-chan models.Progress {
|
|||||||
go func() {
|
go func() {
|
||||||
defer close(out)
|
defer close(out)
|
||||||
if t.stdErrPipe == nil {
|
if t.stdErrPipe == nil {
|
||||||
|
out <- models.Progress{}
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
defer t.stdErrPipe.Close()
|
||||||
}
|
}
|
||||||
scanner := bufio.NewScanner(t.stdErrPipe)
|
scanner := bufio.NewScanner(t.stdErrPipe)
|
||||||
filetype := utils.CheckFileType(t.MediaFile().Metadata().Streams)
|
|
||||||
|
|
||||||
split := func(data []byte, atEOF bool) (advance int, token []byte, spliterror error) {
|
split := func(data []byte, atEOF bool) (advance int, token []byte, spliterror error) {
|
||||||
|
|
||||||
if atEOF && len(data) == 0 {
|
if atEOF && len(data) == 0 {
|
||||||
return 0, nil, nil
|
return 0, nil, nil
|
||||||
}
|
}
|
||||||
|
if i := bytes.IndexByte(data, '\n'); i >= 0 {
|
||||||
Iframe := strings.Index(string(data), "frame=")
|
// We have a full newline-terminated line.
|
||||||
|
return i + 1, data[0:i], nil
|
||||||
if filetype == "video" {
|
}
|
||||||
if Iframe > 0 {
|
if i := bytes.IndexByte(data, '\r'); i >= 0 {
|
||||||
return Iframe + 1, data[Iframe:], nil
|
// We have a cr terminated line
|
||||||
}
|
return i + 1, data[0:i], 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 {
|
if atEOF {
|
||||||
return len(data), data, nil
|
return len(data), data, nil
|
||||||
}
|
}
|
||||||
@@ -195,20 +186,18 @@ func (t Transcoder) Output() <-chan models.Progress {
|
|||||||
buf := make([]byte, 2)
|
buf := make([]byte, 2)
|
||||||
scanner.Buffer(buf, bufio.MaxScanTokenSize)
|
scanner.Buffer(buf, bufio.MaxScanTokenSize)
|
||||||
|
|
||||||
var lastProgress float64
|
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
Progress := new(models.Progress)
|
Progress := new(models.Progress)
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
// fmt.Println(line)
|
if strings.Contains(line, "frame=") && strings.Contains(line, "time=") && strings.Contains(line, "bitrate=") {
|
||||||
if strings.Contains(line, "time=") && strings.Contains(line, "bitrate=") {
|
|
||||||
var re= regexp.MustCompile(`=\s+`)
|
var re= regexp.MustCompile(`=\s+`)
|
||||||
st := re.ReplaceAllString(line, `=`)
|
st := re.ReplaceAllString(line, `=`)
|
||||||
|
|
||||||
f := strings.Fields(st)
|
f := strings.Fields(st)
|
||||||
|
|
||||||
var framesProcessed string
|
var framesProcessed string
|
||||||
var currentTime string
|
var currentTime string
|
||||||
var currentBitrate string
|
var currentBitrate string
|
||||||
|
var currentSpeed string
|
||||||
|
|
||||||
for j := 0; j < len(f); j++ {
|
for j := 0; j < len(f); j++ {
|
||||||
field := f[j]
|
field := f[j]
|
||||||
@@ -229,23 +218,25 @@ func (t Transcoder) Output() <-chan models.Progress {
|
|||||||
if fieldname == "bitrate" {
|
if fieldname == "bitrate" {
|
||||||
currentBitrate = fieldvalue
|
currentBitrate = fieldvalue
|
||||||
}
|
}
|
||||||
|
if fieldname == "speed" {
|
||||||
|
currentSpeed = fieldvalue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timesec := utils.DurToSec(currentTime)
|
timesec := utils.DurToSec(currentTime)
|
||||||
dursec, _ := strconv.ParseFloat(t.MediaFile().Metadata().Format.Duration, 64)
|
dursec, _ := strconv.ParseFloat(t.MediaFile().Metadata().Format.Duration, 64)
|
||||||
// Progress calculation
|
//live stream check
|
||||||
progress := (timesec * 100) / dursec
|
if dursec != 0 {
|
||||||
|
// Progress calculation
|
||||||
Progress.Progress = progress
|
progress := (timesec * 100) / dursec
|
||||||
|
Progress.Progress = progress
|
||||||
|
}
|
||||||
Progress.CurrentBitrate = currentBitrate
|
Progress.CurrentBitrate = currentBitrate
|
||||||
Progress.FramesProcessed = framesProcessed
|
Progress.FramesProcessed = framesProcessed
|
||||||
Progress.CurrentTime = currentTime
|
Progress.CurrentTime = currentTime
|
||||||
|
Progress.Speed = currentSpeed
|
||||||
if progress != lastProgress {
|
out <- *Progress
|
||||||
lastProgress = progress
|
|
||||||
out <- *Progress
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
Reference in New Issue
Block a user