Fixed leak of goroutine and channel in Video.cleanup()

This commit is contained in:
Giuseppe Coviello 2024-01-23 13:37:58 -05:00
parent cf92b10b6b
commit afcc49ec6c

View file

@ -27,6 +27,9 @@ type Video struct {
metadata map[string]string // Video metadata. metadata map[string]string // Video metadata.
pipe io.ReadCloser // Stdout pipe for ffmpeg process. pipe io.ReadCloser // Stdout pipe for ffmpeg process.
cmd *exec.Cmd // ffmpeg command. cmd *exec.Cmd // ffmpeg command.
closeCleanupChan chan struct{} // exit from cleanup goroutine to avoid chan and goroutine leak
cleanupClosed bool
} }
func (video *Video) FileName() string { func (video *Video) FileName() string {
@ -150,6 +153,8 @@ func NewVideoStreams(filename string) ([]*Video, error) {
stream: i, stream: i,
hasstreams: hasstream, hasstreams: hasstream,
metadata: data, metadata: data,
closeCleanupChan: make(chan struct{}, 1),
} }
video.addVideoData(data) video.addVideoData(data)
@ -384,6 +389,11 @@ func (video *Video) ReadFrames(n ...int) ([]*image.RGBA, error) {
// Closes the pipe and stops the ffmpeg process. // Closes the pipe and stops the ffmpeg process.
func (video *Video) Close() { func (video *Video) Close() {
if !video.cleanupClosed {
video.cleanupClosed = true
video.closeCleanupChan <- struct{}{}
close(video.closeCleanupChan)
}
if video.pipe != nil { if video.pipe != nil {
video.pipe.Close() video.pipe.Close()
} }
@ -398,13 +408,18 @@ func (video *Video) cleanup() {
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM) signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() { go func() {
<-c select {
if video.pipe != nil { case <-c:
video.pipe.Close() if video.pipe != nil {
video.pipe.Close()
}
if video.cmd != nil {
video.cmd.Process.Kill()
}
os.Exit(1)
case <-video.closeCleanupChan:
signal.Stop(c)
close(c)
} }
if video.cmd != nil {
video.cmd.Process.Kill()
}
os.Exit(1)
}() }()
} }