Skip to content

Instantly share code, notes, and snippets.

@browny
Last active October 28, 2023 23:55
Show Gist options
  • Save browny/08a46da180a18f3c5d9397201aa5f889 to your computer and use it in GitHub Desktop.
Save browny/08a46da180a18f3c5d9397201aa5f889 to your computer and use it in GitHub Desktop.
Capture ffmpeg output when executed by Go os/exec pkg
package main
import (
"bufio"
"flag"
"fmt"
"os/exec"
"regexp"
"strings"
)
var (
file = flag.String("file", "", "video file")
rtmp = flag.String("rtmp", "", "RTMP URL")
)
func main() {
flag.Parse()
args := fmt.Sprintf("-re -i %s -c copy -f flv %s", *file, *rtmp)
cmd := exec.Command("ffmpeg", strings.Split(args, " ")...)
stdErr, err := cmd.StderrPipe()
if err != nil {
panic(err)
}
err = cmd.Start()
if err != nil {
panic(err)
}
scanner := bufio.NewScanner(stdErr)
scanner.Split(rawScan)
for scanner.Scan() {
m := scanner.Text()
info := info(m)
if len(info) > 0 {
fmt.Printf("%+v\n", info)
}
}
err = cmd.Wait()
if err != nil {
fmt.Printf("err: %s\n", err)
return
}
fmt.Println("finished")
}
func info(data string) map[string]string {
myExp := regexp.MustCompile(`frame=(?P<frame>.*)fps=(?P<fps>.*)q=(?P<q>.*)size=(?P<size>.*)` +
`time=(?P<time>.*)bitrate=(?P<bitrate>.*)speed=(?P<speed>.*)`)
result := map[string]string{}
if !myExp.Match([]byte(data)) {
return result
}
matches := myExp.FindStringSubmatch(data)
names := myExp.SubexpNames()
for i, m := range matches {
if names[i] == "" {
continue
}
result[names[i]] = strings.TrimSpace(m)
}
return result
}
// dropCR drops a terminal \r from the data.
func dropCR(data []byte) []byte {
if len(data) > 0 && data[len(data)-1] == '\r' {
return data[0 : len(data)-1]
}
return data
}
func rawScan(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
return len(data), dropCR(data), nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment