mirror of https://github.com/stashapp/stash.git
77 lines
1.9 KiB
Go
77 lines
1.9 KiB
Go
|
package ffmpeg
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"math"
|
||
|
"regexp"
|
||
|
"strconv"
|
||
|
)
|
||
|
|
||
|
// FrameInfo contains the number of frames and the frame rate for a video file.
|
||
|
type FrameInfo struct {
|
||
|
FrameRate float64
|
||
|
NumberOfFrames int
|
||
|
}
|
||
|
|
||
|
// CalculateFrameRate calculates the frame rate and number of frames of the video file.
|
||
|
// Used where the frame rate or NbFrames is missing or invalid in the ffprobe output.
|
||
|
func (f FFMpeg) CalculateFrameRate(ctx context.Context, v *VideoFile) (*FrameInfo, error) {
|
||
|
var args Args
|
||
|
args = append(args, "-nostats")
|
||
|
args = args.Input(v.Path).
|
||
|
VideoCodec(VideoCodecCopy).
|
||
|
Format(FormatRawVideo).
|
||
|
Overwrite().
|
||
|
NullOutput()
|
||
|
|
||
|
command := f.Command(ctx, args)
|
||
|
var stdErrBuffer bytes.Buffer
|
||
|
command.Stderr = &stdErrBuffer // Frames go to stderr rather than stdout
|
||
|
err := command.Run()
|
||
|
if err == nil {
|
||
|
var ret FrameInfo
|
||
|
stdErrString := stdErrBuffer.String()
|
||
|
ret.NumberOfFrames = getFrameFromRegex(stdErrString)
|
||
|
|
||
|
time := getTimeFromRegex(stdErrString)
|
||
|
ret.FrameRate = math.Round((float64(ret.NumberOfFrames)/time)*100) / 100
|
||
|
|
||
|
return &ret, nil
|
||
|
}
|
||
|
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
var timeRegex = regexp.MustCompile(`time=\s*(\d+):(\d+):(\d+.\d+)`)
|
||
|
var frameRegex = regexp.MustCompile(`frame=\s*([0-9]+)`)
|
||
|
|
||
|
func getTimeFromRegex(str string) float64 {
|
||
|
regexResult := timeRegex.FindStringSubmatch(str)
|
||
|
|
||
|
// Bail early if we don't have the results we expect
|
||
|
if len(regexResult) != 4 {
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
h, _ := strconv.ParseFloat(regexResult[1], 64)
|
||
|
m, _ := strconv.ParseFloat(regexResult[2], 64)
|
||
|
s, _ := strconv.ParseFloat(regexResult[3], 64)
|
||
|
hours := h * 3600
|
||
|
minutes := m * 60
|
||
|
seconds := s
|
||
|
return hours + minutes + seconds
|
||
|
}
|
||
|
|
||
|
func getFrameFromRegex(str string) int {
|
||
|
regexResult := frameRegex.FindStringSubmatch(str)
|
||
|
|
||
|
// Bail early if we don't have the results we expect
|
||
|
if len(regexResult) < 2 {
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
result, _ := strconv.Atoi(regexResult[1])
|
||
|
return result
|
||
|
}
|