package video import ( "context" "os" "path/filepath" "testing" ) func TestCanRemux(t *testing.T) { base := func() *Info { return &Info{ VideoCodec: "h264", PixelFormat: "yuv420p", Profile: "High", AudioCodec: "aac", Container: "mov,mp4,m4a,3gp,3g2,mj2", Width: 1920, Height: 1080, } } cases := []struct { name string mut func(*Info) cap int want bool }{ {"web compatible", func(*Info) {}, MaxLongSide, true}, {"no audio", func(i *Info) { i.AudioCodec = "" }, MaxLongSide, true}, {"empty profile accepted", func(i *Info) { i.Profile = "" }, MaxLongSide, true}, {"hevc", func(i *Info) { i.VideoCodec = "hevc" }, MaxLongSide, false}, {"vp9", func(i *Info) { i.VideoCodec = "vp9" }, MaxLongSide, false}, {"yuv444p", func(i *Info) { i.PixelFormat = "yuv444p" }, MaxLongSide, false}, {"ten bit profile", func(i *Info) { i.Profile = "High 10" }, MaxLongSide, false}, {"mp3 audio", func(i *Info) { i.AudioCodec = "mp3" }, MaxLongSide, false}, {"mpegts container", func(i *Info) { i.Container = "mpegts" }, MaxLongSide, false}, {"mkv h264 remuxable", func(i *Info) { i.Container = "matroska,webm" }, MaxLongSide, true}, {"over cap", func(i *Info) { i.Width = 3840; i.Height = 2160 }, MaxLongSide, false}, {"cap disabled", func(i *Info) { i.Width = 3840; i.Height = 2160 }, 0, true}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { i := base() tc.mut(i) if got := i.CanRemux(tc.cap); got != tc.want { t.Fatalf("CanRemux = %v, want %v (%+v)", got, tc.want, i) } }) } } func writeFakeTool(t *testing.T, body string) string { t.Helper() dir := t.TempDir() path := filepath.Join(dir, "ffprobe") script := "#!/bin/sh\ncat <<'JSON'\n" + body + "\nJSON\n" if err := os.WriteFile(path, []byte(script), 0o755); err != nil { t.Fatalf("write fake tool: %v", err) } return path } func TestProbeParsesOutput(t *testing.T) { probe := writeFakeTool(t, `{"streams":[{"codec_type":"video","codec_name":"h264","profile":"High","pix_fmt":"yuv420p","width":1920,"height":1080,"side_data_list":[{"rotation":-90}]},{"codec_type":"audio","codec_name":"aac"}],"format":{"format_name":"mov,mp4,m4a,3gp,3g2,mj2","duration":"12.345678"}}`) info, err := Probe(context.Background(), probe, "input.mp4") if err != nil { t.Fatalf("probe: %v", err) } if info.VideoCodec != "h264" || info.PixelFormat != "yuv420p" || info.AudioCodec != "aac" { t.Fatalf("codecs = %+v", info) } if info.Width != 1920 || info.Height != 1080 || info.LongSide() != 1920 { t.Fatalf("dimensions = %+v", info) } if info.Rotation != 270 { t.Fatalf("rotation = %d, want 270", info.Rotation) } if info.DurationMS != 12346 { t.Fatalf("duration = %d, want 12346", info.DurationMS) } if !info.CanRemux(MaxLongSide) { t.Fatalf("expected remuxable, got %+v", info) } } func TestProbeFailsOnNonZeroExit(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "ffprobe") if err := os.WriteFile(path, []byte("#!/bin/sh\necho boom >&2\nexit 1\n"), 0o755); err != nil { t.Fatalf("write: %v", err) } if _, err := Probe(context.Background(), path, "x"); err == nil { t.Fatal("expected probe error") } }