Files
ffmpeg-go/examples/stream.go
2020-11-11 14:06:04 +08:00

156 lines
3.2 KiB
Go

package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"sync"
ffmpeg "github.com/u2takey/ffmpeg-go"
)
var (
InputFile = flag.String("in_filename", "./in1.mp4", "Input filename")
OutputFile = flag.String("out_filename", "./out.mp4", "Input filename")
Dream = flag.Bool("dream", false, "Use DeepDream frame processing (requires tensorflow)")
)
// Buffer is a goroutine safe bytes.Buffer
type Buffer struct {
buffer bytes.Buffer
mutex sync.Mutex
}
func (s *Buffer) Write(p []byte) (n int, err error) {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.buffer.Write(p)
}
func (s *Buffer) Read(p []byte) (n int, err error) {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.buffer.Read(p)
}
func getVideoSize(fileName string) (int, int) {
log.Println("Getting video size for", fileName)
data, err := ffmpeg.Probe(fileName)
if err != nil {
panic(err)
}
log.Println("got video info", data)
type VideoInfo struct {
Streams []struct {
CodecType string `json:"codec_type"`
Width int
Height int
} `json:"streams"`
}
vInfo := &VideoInfo{}
err = json.Unmarshal([]byte(data), vInfo)
if err != nil {
panic(err)
}
for _, s := range vInfo.Streams {
if s.CodecType == "video" {
return s.Width, s.Height
}
}
return 0, 0
}
func startFFmpegProcess1(infileName string, writer io.WriteCloser) <-chan error {
log.Println("Starting ffmpeg process1")
done := make(chan error)
go func() {
err := ffmpeg.Input(infileName).
Output("pipe:",
ffmpeg.KwArgs{
"format": "rawvideo", "pix_fmt": "rgb24",
}).
WithOutput(writer).
Run()
log.Println("ffmpeg process1 done")
_ = writer.Close()
done <- err
close(done)
}()
return done
}
func startFFmpegProcess2(outfileName string, buf io.Reader, width, height int) <-chan error {
log.Println("Starting ffmpeg process2")
done := make(chan error)
go func() {
err := ffmpeg.Input("pipe:",
ffmpeg.KwArgs{"format": "rawvideo",
"pix_fmt": "rgb24", "s": fmt.Sprintf("%dx%d", width, height),
}).
Output(outfileName, ffmpeg.KwArgs{"pix_fmt": "yuv420p"}).
OverWriteOutput().
WithInput(buf).
Run()
log.Println("ffmpeg process2 done")
done <- err
close(done)
}()
return done
}
func process(reader io.ReadCloser, writer io.WriteCloser, w, h int) {
go func() {
frameSize := w * h * 3
buf := make([]byte, frameSize, frameSize)
for {
n, err := io.ReadFull(reader, buf)
if n == 0 || err == io.EOF {
_ = writer.Close()
return
} else if n != frameSize || err != nil {
panic(fmt.Sprintf("read error: %d, %s", n, err))
}
for i := range buf {
buf[i] = buf[i] / 3
}
n, err = writer.Write(buf)
if n != frameSize || err != nil {
panic(fmt.Sprintf("write error: %d, %s", n, err))
}
}
}()
return
}
func run(inFile, outFile string) {
w, h := getVideoSize(inFile)
log.Println(w, h)
pr1, pw1 := io.Pipe()
pr2, pw2 := io.Pipe()
done1 := startFFmpegProcess1(inFile, pw1)
process(pr1, pw2, w, h)
done2 := startFFmpegProcess2(outFile, pr2, w, h)
err := <-done1
if err != nil {
panic(err)
}
err = <-done2
if err != nil {
panic(err)
}
log.Println("Done")
}
func main() {
flag.Parse()
if *Dream == true {
fmt.Println("tensorflow mode not implemented, todo")
return
}
run(*InputFile, *OutputFile)
}