mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Restructure ffmpeg (#2392)
* Refactor transcode generation * Move phash generation into separate package * Refactor image thumbnail generation * Move JSONTime to separate package * Ffmpeg refactoring * Refactor live transcoding * Refactor scene marker preview generation * Refactor preview generation * Refactor screenshot generation * Refactor sprite generation * Change ffmpeg.IsStreamable to return error * Move frame rate calculation into ffmpeg * Refactor file locking * Refactor title set during scan * Add missing lockmanager instance * Return error instead of logging in MatchContainer
This commit is contained in:
76
pkg/ffmpeg/frame_rate.go
Normal file
76
pkg/ffmpeg/frame_rate.go
Normal file
@@ -0,0 +1,76 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user