package ffmpeg_go import ( "bytes" "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/u2takey/go-utils/rand" ) const ( TestInputFile1 = "./examples/sample_data/in1.mp4" TestOutputFile1 = "./examples/sample_data/out1.mp4" TestOverlayFile = "./examples/sample_data/overlay.png" ) func TestFluentEquality(t *testing.T) { base1 := Input("dummy1.mp4") base2 := Input("dummy1.mp4") base3 := Input("dummy2.mp4") t1 := base1.Trim(KwArgs{"start_frame": 10, "end_frame": 20}) t2 := base1.Trim(KwArgs{"start_frame": 10, "end_frame": 20}) t3 := base1.Trim(KwArgs{"start_frame": 10, "end_frame": 30}) t4 := base2.Trim(KwArgs{"start_frame": 10, "end_frame": 20}) t5 := base3.Trim(KwArgs{"start_frame": 10, "end_frame": 20}) assert.Equal(t, t1.Hash(), t2.Hash()) assert.Equal(t, t1.Hash(), t4.Hash()) assert.NotEqual(t, t1.Hash(), t3.Hash()) assert.NotEqual(t, t1.Hash(), t5.Hash()) } func TestFluentConcat(t *testing.T) { base1 := Input("dummy1.mp4", nil) trim1 := base1.Trim(KwArgs{"start_frame": 10, "end_frame": 20}) trim2 := base1.Trim(KwArgs{"start_frame": 30, "end_frame": 40}) trim3 := base1.Trim(KwArgs{"start_frame": 50, "end_frame": 60}) concat1 := Concat([]*Stream{trim1, trim2, trim3}) concat2 := Concat([]*Stream{trim1, trim2, trim3}) concat3 := Concat([]*Stream{trim1, trim3, trim2}) assert.Equal(t, concat1.Hash(), concat2.Hash()) assert.NotEqual(t, concat1.Hash(), concat3.Hash()) } func TestRepeatArgs(t *testing.T) { o := Input("dummy.mp4", nil).Output("dummy2.mp4", KwArgs{"streamid": []string{"0:0x101", "1:0x102"}}) assert.Equal(t, o.GetArgs(), []string{"-i", "dummy.mp4", "-streamid", "0:0x101", "-streamid", "1:0x102", "dummy2.mp4"}) } func TestGlobalArgs(t *testing.T) { o := Input("dummy.mp4", nil).Output("dummy2.mp4", nil).GlobalArgs("-progress", "someurl") assert.Equal(t, o.GetArgs(), []string{ "-i", "dummy.mp4", "dummy2.mp4", "-progress", "someurl", }) } func TestSimpleExample(t *testing.T) { err := Input(TestInputFile1, nil). Output(TestOutputFile1, nil). OverWriteOutput(). Run() assert.Nil(t, err) } func TestSimpleOverLayExample(t *testing.T) { err := Input(TestInputFile1, nil). Overlay(Input(TestOverlayFile), ""). Output(TestOutputFile1).OverWriteOutput(). Run() assert.Nil(t, err) } func TestSimpleOutputArgs(t *testing.T) { cmd := Input(TestInputFile1).Output("imageFromVideo_%d.jpg", KwArgs{"vf": "fps=3", "qscale:v": 2}) assert.Equal(t, []string{ "-i", "./examples/sample_data/in1.mp4", "-qscale:v", "2", "-vf", "fps=3", "imageFromVideo_%d.jpg"}, cmd.GetArgs()) } func TestAutomaticStreamSelection(t *testing.T) { // example from http://ffmpeg.org/ffmpeg-all.html input := []*Stream{Input("A.avi"), Input("B.mp4")} out1 := Output(input, "out1.mkv") out2 := Output(input, "out2.wav") out3 := Output(input, "out3.mov", KwArgs{"map": "1:a", "c:a": "copy"}) cmd := MergeOutputs(out1, out2, out3) printArgs(cmd.GetArgs()) printGraph(cmd) } func TestLabeledFiltergraph(t *testing.T) { // example from http://ffmpeg.org/ffmpeg-all.html in1, in2, in3 := Input("A.avi"), Input("B.mp4"), Input("C.mkv") in2Split := in2.Get("v").Hue(KwArgs{"s": 0}).Split() overlay := Filter([]*Stream{in1, in2}, "overlay", nil) aresample := Filter([]*Stream{in1, in2, in3}, "aresample", nil) out1 := Output([]*Stream{in2Split.Get("outv1"), overlay, aresample}, "out1.mp4", KwArgs{"an": ""}) out2 := Output([]*Stream{in1, in2, in3}, "out2.mkv") out3 := in2Split.Get("outv2").Output("out3.mkv", KwArgs{"map": "1:a:0"}) cmd := MergeOutputs(out1, out2, out3) printArgs(cmd.GetArgs()) printGraph(cmd) } func ComplexFilterExample() *Stream { split := Input(TestInputFile1).VFlip().Split() split0, split1 := split.Get("0"), split.Get("1") overlayFile := Input(TestOverlayFile).Crop(10, 10, 158, 112) return Concat([]*Stream{ split0.Trim(KwArgs{"start_frame": 10, "end_frame": 20}), split1.Trim(KwArgs{"start_frame": 30, "end_frame": 40})}). Overlay(overlayFile.HFlip(), ""). DrawBox(50, 50, 120, 120, "red", 5). Output(TestOutputFile1). OverWriteOutput() } func TestComplexFilterExample(t *testing.T) { assert.Equal(t, []string{ "-i", TestInputFile1, "-i", TestOverlayFile, "-filter_complex", "[0]vflip[s0];" + "[s0]split=2[s1][s2];" + "[s1]trim=end_frame=20:start_frame=10[s3];" + "[s2]trim=end_frame=40:start_frame=30[s4];" + "[s3][s4]concat=n=2[s5];" + "[1]crop=158:112:10:10[s6];" + "[s6]hflip[s7];" + "[s5][s7]overlay=eof_action=repeat[s8];" + "[s8]drawbox=50:50:120:120:red:t=5[s9]", "-map", "[s9]", TestOutputFile1, "-y", }, ComplexFilterExample().GetArgs()) } func TestCombinedOutput(t *testing.T) { i1 := Input(TestInputFile1) i2 := Input(TestOverlayFile) out := Output([]*Stream{i1, i2}, TestOutputFile1) assert.Equal(t, []string{ "-i", TestInputFile1, "-i", TestOverlayFile, "-map", "0", "-map", "1", TestOutputFile1, }, out.GetArgs()) } func TestFilterWithSelector(t *testing.T) { i := Input(TestInputFile1) v1 := i.Video().HFlip() a1 := i.Audio().Filter("aecho", Args{"0.8", "0.9", "1000", "0.3"}) out := Output([]*Stream{a1, v1}, TestOutputFile1) assert.Equal(t, []string{ "-i", TestInputFile1, "-filter_complex", "[0:a]aecho=0.8:0.9:1000:0.3[s0];[0:v]hflip[s1]", "-map", "[s0]", "-map", "[s1]", TestOutputFile1}, out.GetArgs()) } func ComplexFilterAsplitExample() *Stream { split := Input(TestInputFile1).VFlip().ASplit() split0 := split.Get("0") split1 := split.Get("1") return Concat([]*Stream{ split0.Filter("atrim", nil, KwArgs{"start": 10, "end": 20}), split1.Filter("atrim", nil, KwArgs{"start": 30, "end": 40}), }).Output(TestOutputFile1).OverWriteOutput() } func TestFilterConcatVideoOnly(t *testing.T) { in1 := Input("in1.mp4") in2 := Input("in2.mp4") args := Concat([]*Stream{in1, in2}).Output("out.mp4").GetArgs() assert.Equal(t, []string{ "-i", "in1.mp4", "-i", "in2.mp4", "-filter_complex", "[0][1]concat=n=2[s0]", "-map", "[s0]", "out.mp4", }, args) } func TestFilterConcatAudioOnly(t *testing.T) { in1 := Input("in1.mp4") in2 := Input("in2.mp4") args := Concat([]*Stream{in1, in2}, KwArgs{"v": 0, "a": 1}).Output("out.mp4").GetArgs() assert.Equal(t, []string{ "-i", "in1.mp4", "-i", "in2.mp4", "-filter_complex", "[0][1]concat=a=1:n=2:v=0[s0]", "-map", "[s0]", "out.mp4", }, args) } func TestFilterConcatAudioVideo(t *testing.T) { in1 := Input("in1.mp4") in2 := Input("in2.mp4") joined := Concat([]*Stream{in1.Video(), in1.Audio(), in2.HFlip(), in2.Get("a")}, KwArgs{"v": 1, "a": 1}).Node args := Output([]*Stream{joined.Get("0"), joined.Get("1")}, "out.mp4").GetArgs() assert.Equal(t, []string{ "-i", "in1.mp4", "-i", "in2.mp4", "-filter_complex", "[1]hflip[s0];[0:v][0:a][s0][1:a]concat=a=1:n=2:v=1[s1][s2]", "-map", "[s1]", "-map", "[s2]", "out.mp4", }, args) } func TestFilterASplit(t *testing.T) { out := ComplexFilterAsplitExample() args := out.GetArgs() assert.Equal(t, []string{ "-i", TestInputFile1, "-filter_complex", "[0]vflip[s0];[s0]asplit=2[s1][s2];[s1]atrim=end=20:start=10[s3];[s2]atrim=end=40:start=30[s4];[s3][s4]concat=n=2[s5]", "-map", "[s5]", TestOutputFile1, "-y", }, args) } func TestOutputBitrate(t *testing.T) { args := Input("in").Output("out", KwArgs{"video_bitrate": 1000, "audio_bitrate": 200}).GetArgs() assert.Equal(t, []string{"-i", "in", "-b:v", "1000", "-b:a", "200", "out"}, args) } func TestOutputVideoSize(t *testing.T) { args := Input("in").Output("out", KwArgs{"video_size": "320x240"}).GetArgs() assert.Equal(t, []string{"-i", "in", "-video_size", "320x240", "out"}, args) } func TestCompile(t *testing.T) { out := Input("dummy.mp4").Output("dummy2.mp4") assert.Equal(t, out.Compile().Args, []string{"ffmpeg", "-i", "dummy.mp4", "dummy2.mp4"}) } func TestPipe(t *testing.T) { width, height := 32, 32 frameSize := width * height * 3 frameCount, startFrame := 10, 2 _, _ = frameCount, frameSize out := Input( "pipe:0", KwArgs{ "format": "rawvideo", "pixel_format": "rgb24", "video_size": fmt.Sprintf("%dx%d", width, height), "framerate": 10}). Trim(KwArgs{"start_frame": startFrame}). Output("pipe:1", KwArgs{"format": "rawvideo"}) args := out.GetArgs() assert.Equal(t, args, []string{ "-f", "rawvideo", "-video_size", fmt.Sprintf("%dx%d", width, height), "-framerate", "10", "-pixel_format", "rgb24", "-i", "pipe:0", "-filter_complex", "[0]trim=start_frame=2[s0]", "-map", "[s0]", "-f", "rawvideo", "pipe:1", }) inBuf := bytes.NewBuffer(nil) for i := 0; i < frameSize*frameCount; i++ { inBuf.WriteByte(byte(rand.IntnRange(0, 255))) } outBuf := bytes.NewBuffer(nil) err := out.WithInput(inBuf).WithOutput(outBuf).Run() assert.Nil(t, err) assert.Equal(t, outBuf.Len(), frameSize*(frameCount-startFrame)) } func TestView(t *testing.T) { a, err := ComplexFilterExample().View(ViewTypeFlowChart) assert.Nil(t, err) b, err := ComplexFilterAsplitExample().View(ViewTypeStateDiagram) assert.Nil(t, err) t.Log(a) t.Log(b) } func printArgs(args []string) { for _, a := range args { fmt.Printf("%s ", a) } fmt.Println() } func printGraph(s *Stream) { fmt.Println() v, _ := s.View(ViewTypeFlowChart) fmt.Println(v) } //func TestAvFoundation(t *testing.T) { // out := Input("default:none", KwArgs{"f": "avfoundation", "framerate": "30"}). // Output("output.mp4", KwArgs{"format": "mp4"}). // OverWriteOutput() // assert.Equal(t, []string{"-f", "avfoundation", "-framerate", // "30", "-i", "default:none", "-f", "mp4", "output.mp4", "-y"}, out.GetArgs()) // err := out.Run() // assert.Nil(t, err) //}