Moved all to videoio.go for portability

This commit is contained in:
Alex Eidt 2021-12-22 15:51:37 -08:00
parent ff24be3154
commit 3faf4aa9c8
7 changed files with 316 additions and 340 deletions

114
video.go
View file

@ -1,114 +0,0 @@
package main
import (
"io"
"os"
"os/exec"
"os/signal"
"syscall"
)
type Video struct {
filename string
width int
height int
channels int
bitrate int
duration float64
fps float64
codec string
pix_fmt string
framebuffer []byte
pipe *io.ReadCloser
cmd *exec.Cmd
}
func NewVideo(filename string) *Video {
if !Exists(filename) {
panic("File: " + filename + " does not exist")
}
// Execute ffmpeg -i command to get video information.
cmd := exec.Command("ffmpeg", "-i", filename, "-")
// ffmpeg output piped to Stderr.
pipe, err := cmd.StderrPipe()
if err != nil {
panic(err)
}
if err := cmd.Start(); err != nil {
panic(err)
}
buffer := make([]byte, 2<<12)
total := 0
for {
n, err := pipe.Read(buffer[total:])
total += n
if err == io.EOF {
break
}
}
cmd.Wait()
video := &Video{filename: filename, channels: 3}
parseFFMPEGHeader(video, string(buffer))
return video
}
func (video *Video) initVideoStream() {
// If user exits with Ctrl+C, stop ffmpeg process.
video.cleanup()
cmd := exec.Command(
"ffmpeg",
"-loglevel", "quiet",
"-i", video.filename,
"-f", "image2pipe",
"-pix_fmt", "rgb24",
"-vcodec", "rawvideo", "-",
)
video.cmd = cmd
pipe, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
video.pipe = &pipe
if err := cmd.Start(); err != nil {
panic(err)
}
video.framebuffer = make([]byte, video.width*video.height*video.channels)
}
func (video *Video) NextFrame() bool {
// If cmd is nil, video reading has not been initialized.
if video.cmd == nil {
video.initVideoStream()
}
total := 0
for total < video.width*video.height*video.channels {
n, err := (*video.pipe).Read(video.framebuffer[total:])
if err == io.EOF {
(*video.pipe).Close()
if err := video.cmd.Wait(); err != nil {
panic(err)
}
return false
}
total += n
}
return true
}
// Stops the "cmd" process running when the user presses Ctrl+C.
// https://stackoverflow.com/questions/11268943/is-it-possible-to-capture-a-ctrlc-signal-and-run-a-cleanup-function-in-a-defe
func (video *Video) cleanup() {
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
if video.pipe != nil {
(*video.pipe).Close()
}
if video.cmd != nil {
video.cmd.Process.Kill()
}
os.Exit(1)
}()
}