78 lines
1.7 KiB
Go
78 lines
1.7 KiB
Go
package utilities
|
|
|
|
import (
|
|
"fmt"
|
|
"gopkg.in/yaml.v3"
|
|
"math"
|
|
"time"
|
|
)
|
|
|
|
type Ratio struct {
|
|
Numerator int
|
|
Denominator int
|
|
}
|
|
|
|
func (r Ratio) Float64() float64 {
|
|
return float64(r.Numerator) / float64(r.Denominator)
|
|
}
|
|
|
|
func (r Ratio) PTSToDuration(pts int64) time.Duration {
|
|
return (time.Duration(pts) * time.Second * time.Duration(r.Numerator)) / time.Duration(r.Denominator)
|
|
}
|
|
|
|
func (r *Ratio) UnmarshalJSON(buf []byte) error {
|
|
_, err := fmt.Sscanf(string(buf), "\"%d:%d\"", &r.Numerator, &r.Denominator)
|
|
return err
|
|
}
|
|
|
|
func (r *Ratio) UnmarshalYAML(node *yaml.Node) error {
|
|
_, err := fmt.Sscanf(node.Value, "%d:%d", &r.Numerator, &r.Denominator)
|
|
return err
|
|
}
|
|
|
|
func (r Ratio) MarshalJSON() ([]byte, error) {
|
|
return []byte("\"" + r.String() + "\""), nil
|
|
}
|
|
|
|
func (r Ratio) String() string {
|
|
return fmt.Sprintf("%d:%d", r.Numerator, r.Denominator)
|
|
}
|
|
|
|
// Reciprocal get the reciprocal, for example, to convert frame rate into time base
|
|
func (r Ratio) Reciprocal() Ratio {
|
|
return Ratio{Numerator: r.Denominator, Denominator: r.Numerator}
|
|
}
|
|
|
|
const NTSCRatio = float64(1001) / 1000
|
|
|
|
const ratioEpsilon = 1.0e-9
|
|
|
|
func NewRatio(n, d int) Ratio {
|
|
return Ratio{
|
|
Numerator: n,
|
|
Denominator: d,
|
|
}
|
|
}
|
|
|
|
// FPSToRatio Attempt common FPS conversions to ratios
|
|
func FPSToRatio(fps float64) Ratio {
|
|
// common NTSC
|
|
ntscValue := fps * NTSCRatio
|
|
|
|
// Number is whole NTSC
|
|
if math.Abs(ntscValue-math.Round(ntscValue)) < ratioEpsilon {
|
|
return NewRatio(int(math.Round(ntscValue))*1000, 1001)
|
|
}
|
|
|
|
// Number is whole other
|
|
if math.Abs(fps-math.Round(fps)) < ratioEpsilon {
|
|
return NewRatio(int(math.Round(fps)), 1)
|
|
}
|
|
|
|
// Get a few decimals of precision
|
|
return Ratio{
|
|
Numerator: int(fps * 1000),
|
|
Denominator: 1000,
|
|
}
|
|
}
|