video config construction refactoring
This commit is contained in:
+94
-68
@@ -4,7 +4,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -18,8 +18,9 @@ import (
|
||||
"github.com/qvest-digital/go-mxl/mxl"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
flowdef "mxl-pattern-generator/internal/flow-def"
|
||||
"mxl-pattern-generator/internal/flowdef"
|
||||
"mxl-pattern-generator/internal/generator"
|
||||
"mxl-pattern-generator/internal/video"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -128,6 +129,9 @@ func validateFlowDefPath(label, path string) error {
|
||||
}
|
||||
|
||||
func validateVideoArgs(args *appArgs) error {
|
||||
if _, exists := patterns[args.pattern]; !exists {
|
||||
return fmt.Errorf("unknown video pattern %q (use --list-patterns to see available patterns)", args.pattern)
|
||||
}
|
||||
if args.videoFlowDefFile != "" {
|
||||
return nil
|
||||
}
|
||||
@@ -142,9 +146,6 @@ func validateVideoArgs(args *appArgs) error {
|
||||
return fmt.Errorf("unsupported video FPS %q (supported: %s); use a flow definition for other rates",
|
||||
args.videoFPS, sortedMapKeys(frameRates))
|
||||
}
|
||||
if _, exists := patterns[args.pattern]; !exists {
|
||||
return fmt.Errorf("unknown video pattern %q (use --list-patterns to see available patterns)", args.pattern)
|
||||
}
|
||||
if args.videoUUID == "" {
|
||||
args.videoUUID = uuid.NewString()
|
||||
return nil
|
||||
@@ -356,6 +357,59 @@ func parseArgs(argv []string, stdout, stderr io.Writer) (parseResult, error) {
|
||||
return parseResult{args: args, shouldRun: true}, nil
|
||||
}
|
||||
|
||||
func buildVideoConfig(args appArgs) (video.Config, error) {
|
||||
var definition flowdef.Video
|
||||
if args.videoFlowDefFile != "" {
|
||||
data, err := os.ReadFile(args.videoFlowDefFile)
|
||||
if err != nil {
|
||||
return video.Config{}, fmt.Errorf(
|
||||
"read video flow definition %q: %w",
|
||||
args.videoFlowDefFile,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
definition, err = flowdef.ParseV210Video(data)
|
||||
if err != nil {
|
||||
return video.Config{}, fmt.Errorf(
|
||||
"parse video flow definition %q: %w",
|
||||
args.videoFlowDefFile,
|
||||
err,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
rate, ok := frameRates[args.videoFPS]
|
||||
if !ok {
|
||||
return video.Config{}, fmt.Errorf("unsupported video FPS %q", args.videoFPS)
|
||||
}
|
||||
|
||||
var err error
|
||||
definition, err = flowdef.NewV210Video(
|
||||
args.videoUUID,
|
||||
args.videoWidth,
|
||||
args.videoHeight,
|
||||
flowdef.Rational{
|
||||
Numerator: uint(rate.Num),
|
||||
Denominator: uint(rate.Den),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return video.Config{}, fmt.Errorf(
|
||||
"build video flow definition: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
if _, ok := patterns[args.pattern]; !ok {
|
||||
return video.Config{}, fmt.Errorf("unknown video pattern %q", args.pattern)
|
||||
}
|
||||
|
||||
return video.Config{
|
||||
Definition: definition,
|
||||
Pattern: args.pattern,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
parsed, err := parseArgs(os.Args[1:], os.Stdout, os.Stderr)
|
||||
if err != nil {
|
||||
@@ -368,50 +422,28 @@ func main() {
|
||||
}
|
||||
args := parsed.args
|
||||
|
||||
type videoInfo struct {
|
||||
uuid string
|
||||
width uint
|
||||
height uint
|
||||
fps mxl.Rational
|
||||
}
|
||||
var vi videoInfo
|
||||
var videoFlowDef string
|
||||
if args.videoFlowDefFile == "" {
|
||||
args.videoUUID = "8f1d2a4b-6c3e-4f5a-9b2c-1d7e8a3f0b5d" // TODO: remove before public release
|
||||
vi = videoInfo{
|
||||
uuid: args.videoUUID,
|
||||
width: args.videoWidth,
|
||||
height: args.videoHeight,
|
||||
fps: frameRates[args.videoFPS],
|
||||
}
|
||||
flowDef, err := flowdef.NewFlowDefJSON(
|
||||
flowdef.TYPE_VIDEO,
|
||||
vi.uuid,
|
||||
vi.width,
|
||||
vi.height,
|
||||
uint(vi.fps.Num),
|
||||
uint(vi.fps.Den),
|
||||
)
|
||||
videoFlowDef = flowDef
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create Flow Definition: %v", err)
|
||||
}
|
||||
} else {
|
||||
flowDef, err := flowdef.ReadFlowDefFile(args.videoFlowDefFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not read video flow def .json: %s. Reason: %v", args.videoFlowDefFile, err)
|
||||
}
|
||||
videoFlowDef = flowDef
|
||||
videoCfg, err := buildVideoConfig(args)
|
||||
if err != nil {
|
||||
log.Fatalf("video configuration: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("%s %s", APP_NAME, APP_VER)
|
||||
log.Printf("Domain: %s", args.domain)
|
||||
log.Printf("Video: %dx%d %d/%d", vi.width, vi.height, vi.fps.Num, vi.fps.Den)
|
||||
log.Printf("Video UUID: %s", vi.uuid)
|
||||
log.Printf("Video: %dx%d %d/%d",
|
||||
videoCfg.Width(),
|
||||
videoCfg.Height(),
|
||||
videoCfg.Rate().Num,
|
||||
videoCfg.Rate().Den,
|
||||
)
|
||||
log.Printf("Video ID: %s", videoCfg.ID())
|
||||
|
||||
// TODO: if init failed -> CPU generator
|
||||
videoPattern := patterns[args.pattern]
|
||||
gen, err := generator.NewWGPUGenerator(vi.width, vi.height, videoPattern.kernelPath)
|
||||
videoPattern := patterns[videoCfg.Pattern]
|
||||
gen, err := generator.NewWGPUGenerator(
|
||||
videoCfg.Width(),
|
||||
videoCfg.Height(),
|
||||
videoPattern.kernelPath,
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("wgpu init failed: %v", err)
|
||||
}
|
||||
@@ -427,15 +459,16 @@ func main() {
|
||||
}
|
||||
defer face.Close()
|
||||
if args.overlayX < 0 ||
|
||||
args.overlayX > int(vi.width) ||
|
||||
args.overlayX > int(videoCfg.Width()) ||
|
||||
args.overlayY < 0 ||
|
||||
args.overlayY > int(vi.height) {
|
||||
log.Fatalf("overlay X/Y pos can't be negative or greater, than video width/height")
|
||||
args.overlayY > int(videoCfg.Height()) {
|
||||
log.Fatalf("text overlay position (%d, %d) is outside the %dx%d video frame",
|
||||
args.overlayX, args.overlayY, videoCfg.Width(), videoCfg.Height())
|
||||
}
|
||||
overlay, err = generator.NewTextOverlay(
|
||||
args.textOverlay,
|
||||
int(vi.width),
|
||||
int(vi.height),
|
||||
int(videoCfg.Width()),
|
||||
int(videoCfg.Height()),
|
||||
args.overlayX,
|
||||
args.overlayY,
|
||||
args.overlayPos,
|
||||
@@ -448,16 +481,21 @@ func main() {
|
||||
|
||||
inst, err := mxl.NewInstance(args.domain, "")
|
||||
if err != nil {
|
||||
log.Fatalf("MXL Init Failed: %v", err)
|
||||
log.Fatalf("initialize MXL domain %q: %v", args.domain, err)
|
||||
}
|
||||
defer inst.Close()
|
||||
|
||||
writer, isCreated, err := inst.NewWriter(videoFlowDef)
|
||||
flowJSON, err := json.Marshal(videoCfg.Definition)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create MXL writer: %v", err)
|
||||
log.Fatalf("marshal video flow definition: %v", err)
|
||||
}
|
||||
|
||||
writer, isCreated, err := inst.NewWriter(string(flowJSON))
|
||||
if err != nil {
|
||||
log.Fatalf("create video writer: %v", err)
|
||||
}
|
||||
if !isCreated {
|
||||
log.Printf("reusing existing flow: %s, domain: %s", vi.uuid, args.domain)
|
||||
log.Printf("reusing existing flow: %s, domain: %s", videoCfg.ID(), args.domain)
|
||||
}
|
||||
defer writer.Close()
|
||||
|
||||
@@ -484,18 +522,18 @@ func main() {
|
||||
|
||||
gwa, err := writer.OpenGrain(idx)
|
||||
if err != nil {
|
||||
log.Fatalf("OpenGrain(%d): %v", idx, err)
|
||||
log.Fatalf("open video grain %d: %v", idx, err)
|
||||
}
|
||||
if err := gen.GenerateFrame(gwa.Payload, int(tick)); err != nil {
|
||||
log.Fatalf("GenerateFrame(%d): %v", idx, err)
|
||||
log.Fatalf("generate frame for grain %d: %v", idx, err)
|
||||
}
|
||||
if overlay != nil {
|
||||
if err := overlay.ApplyV210(gwa.Payload); err != nil {
|
||||
log.Fatalf("text overlay: %v", err)
|
||||
log.Fatalf("apply text overlay to grain %d: %v", idx, err)
|
||||
}
|
||||
}
|
||||
if err := gwa.Commit(gwa.TotalSlices, 0); err != nil {
|
||||
log.Fatalf("Commit(%d): %v", idx, err)
|
||||
log.Fatalf("commit video grain %d: %v", idx, err)
|
||||
}
|
||||
|
||||
grainsWritten++
|
||||
@@ -508,15 +546,3 @@ func main() {
|
||||
mxl.SleepNs(mxl.NsUntilIndex(idx, rate))
|
||||
}
|
||||
}
|
||||
|
||||
func run(ctx context.Context, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func runVideo(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func runAudio(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user