Ignite/utilities/timecodes.go
DataHoarder 230d505377
All checks were successful
continuous-integration/drone/push Build is passing
Fixed VFR pts end
2023-11-06 12:03:14 +01:00

114 lines
2.4 KiB
Go

package utilities
import (
"bufio"
"fmt"
"github.com/nethruster/go-fraction"
"io"
"strings"
"time"
)
// Timecodes Entries in milliseconds. First entry includes fallback duration, in time.Duration format
type Timecodes []int64
func (tc Timecodes) FallbackDuration() time.Duration {
return time.Duration(tc[0])
}
func (tc Timecodes) PTS(n int) int64 {
if n >= 0 && (n+1) < len(tc) {
return tc[n+1]
}
return -1
}
const timecodesv1Header = "# timecode format v1"
func ParseTimecodesV1(reader io.Reader) (Timecodes, error) {
var tc Timecodes
scanner := bufio.NewScanner(reader)
// Read header
if !scanner.Scan() {
return nil, io.ErrUnexpectedEOF
}
switch strings.TrimSpace(scanner.Text()) {
case timecodesv1Header:
default:
return nil, fmt.Errorf("unexpected line: %s", strings.TrimSpace(scanner.Text()))
}
// Read assume line
if !scanner.Scan() {
return nil, io.ErrUnexpectedEOF
}
var fps float64
var from, to int64
_, err := fmt.Sscanf(strings.ToLower(strings.TrimSpace(scanner.Text())), "assume %f", &fps)
if err != nil {
return nil, err
}
assumed := FPSToRatio(fps)
assumedFraction, err := fraction.New(assumed.Denominator, assumed.Numerator)
if err != nil {
return nil, err
}
if assumed.Denominator == 1000 {
assumedFraction, err = fraction.FromFloat64(1 / fps)
if err != nil {
return nil, err
}
}
running, err := fraction.New(0, 1000)
if err != nil {
return nil, err
}
var currentFrame int64
//fallback
tc = append(tc, (int64(time.Second)*assumedFraction.Numerator())/assumedFraction.Denominator())
for scanner.Scan() {
line := strings.ReplaceAll(strings.TrimSpace(scanner.Text()), " ", "")
if line == "" || line[0] == '#' {
continue
}
_, err := fmt.Sscanf(strings.ReplaceAll(strings.TrimSpace(scanner.Text()), " ", ""), "%d,%d,%f", &from, &to, &fps)
if err != nil {
return nil, err
}
ratio := FPSToRatio(fps)
frac, err := fraction.New(ratio.Denominator, ratio.Numerator)
if err != nil {
return nil, err
}
if ratio.Denominator == 1000 {
frac, err = fraction.FromFloat64(1 / fps)
if err != nil {
return nil, err
}
}
for ; currentFrame < from; currentFrame++ {
tc = append(tc, (running.Numerator()*1000)/running.Denominator())
running = running.Add(assumedFraction)
}
for ; currentFrame <= to; currentFrame++ {
tc = append(tc, (running.Numerator()*1000)/running.Denominator())
running = running.Add(frac)
}
}
return tc, nil
}