我试图在golang中使用os/exec调用shell命令,该命令将花费一些时间,因此我想检索reatime输出并打印处理后的输出(进度比率数字).
package main
import (
"bufio"
"fmt"
"io"
"os"
"os/exec"
"strings"
)
func main() {
cmdName := "ffmpeg -i t.webm -acodec aac -vcodec libx264 cmd1.mp4"
cmdArgs := strings.Fields(cmdName)
cmd := exec.Command(cmdArgs[0], cmdArgs[1:len(cmdArgs)]...)
stdout, _ := cmd.StdoutPipe()
cmd.Start()
go print(stdout)
cmd.Wait()
}
// to print the processed information when stdout gets a new line
func print(stdout io.ReadCloser) {
r := bufio.NewReader(stdout)
line, _, err := r.ReadLine()
fmt.Println("line: %s err %s", line, err)
}
Run Code Online (Sandbox Code Playgroud)
我希望有一个功能,当命令打印时可以更新屏幕,
ffmpeg命令输出如下:
frame= 101 fps=0.0 q=28.0 size= 91kB time=00:00:04.13 bitrate= 181.2kbits/
frame= 169 fps=168 q=28.0 size= 227kB time=00:00:06.82 bitrate= 272.6kbits/
frame= 231 fps=153 q=28.0 size= 348kB time=00:00:09.31 bitrate= 306.3kbits/
frame= 282 fps=140 q=28.0 size= 499kB time=00:00:11.33 bitrate= 360.8kbits/
Run Code Online (Sandbox Code Playgroud)
事实上,上面的4行是ffmpeg命令输出的最后一行,它不断变化,我想打印出来的变化,就像
18%
44%
69%
100%
Run Code Online (Sandbox Code Playgroud)
我怎么能实现这个目标?
Bro*_*Lin 11
看起来ffmpeg将所有诊断消息("控制台输出")发送到stderr而不是stdout.下面的代码适合我.
package main
import (
"bufio"
"fmt"
"os/exec"
"strings"
)
func main() {
args := "-i test.mp4 -acodec copy -vcodec copy -f flv rtmp://aaa/bbb"
cmd := exec.Command("ffmpeg", strings.Split(args, " ")...)
stderr, _ := cmd.StderrPipe()
cmd.Start()
scanner := bufio.NewScanner(stderr)
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
m := scanner.Text()
fmt.Println(m)
}
cmd.Wait()
}
Run Code Online (Sandbox Code Playgroud)
ffmpeg的版本详述如下.
ffmpeg version 3.0.2 Copyright (c) 2000-2016 the FFmpeg developers
built with Apple LLVM version 7.3.0 (clang-703.0.29)
configuration: --prefix=/usr/local/Cellar/ffmpeg/3.0.2 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-opencl --enable-libx264 --enable-libmp3lame --enable-libxvid --enable-vda
libavutil 55. 17.103 / 55. 17.103
libavcodec 57. 24.102 / 57. 24.102
libavformat 57. 25.100 / 57. 25.100
libavdevice 57. 0.101 / 57. 0.101
libavfilter 6. 31.100 / 6. 31.100
libavresample 3. 0. 0 / 3. 0. 0
libswscale 4. 0.100 / 4. 0.100
libswresample 2. 0.101 / 2. 0.101
libpostproc 54. 0.100 / 54. 0.100
Run Code Online (Sandbox Code Playgroud)
我确实发现他在那篇文章中提到的 icza 解决方案非常有用,但它并没有解决我的问题。
我做了一个小测试如下:
1,我写了一个脚本,每秒打印一些信息十次,这是 script.sh
#!/bin/bash
for i in {1..10}
do
echo "step " $i
sleep 1s
done
Run Code Online (Sandbox Code Playgroud)
2、读取stdout并从stdout中提取所需的信息并进行一些处理以获得预期的格式,代码如下:package main
import (
"fmt"
"os/exec"
"regexp"
"strconv"
"strings"
)
func getRatio(text string) float32 {
re1, _ := regexp.Compile(`step[\s]+(\d+)`)
result := re1.FindStringSubmatch(text)
val, _ := strconv.Atoi(result[1])
return float32(val) / 10
}
func main() {
cmdName := "ffmpeg -i t.webm -acodec aac -vcodec libx264 cmd1.mp4"
//cmdName := "bash ./script.sh"
cmdArgs := strings.Fields(cmdName)
cmd := exec.Command(cmdArgs[0], cmdArgs[1:len(cmdArgs)]...)
stdout, _ := cmd.StdoutPipe()
cmd.Start()
oneByte := make([]byte, 10)
for {
_, err := stdout.Read(oneByte)
if err != nil {
break
}
progressingRatio := getRatio(string(oneByte))
fmt.Printf("progressing ratio %v \n", progressingRatio)
}
}
Run Code Online (Sandbox Code Playgroud)
这确实适用于我的 script.sh 测试,但对于 ffmpeg 命令它不起作用,在 ffmpeg 的情况下,没有打印任何内容并且过程完成(没有卡住),我想将数据写入 ffmpeg 的标准输出的方式是有点特别(也许根本没有换行符,我尝试了icza的解决方案,但它仍然不起作用)。