diff --git a/README b/README deleted file mode 100644 index 904a2e8..0000000 --- a/README +++ /dev/null @@ -1,5 +0,0 @@ -# ffmpeg-go - -ffmpeg-go is golang port of https://github.com/kkroening/ffmpeg-python - -check ffmpeg_test.go for examples. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e82129a --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# ffmpeg-go + +ffmpeg-go is golang port of https://github.com/kkroening/ffmpeg-python + +check ffmpeg_test.go for examples. + + +# example + +```go +split := Input(TestInputFile1).VFlip().Split() + split0, split1 := split.Get("0"), split.Get("1") + overlayFile := Input(TestOverlayFile).Crop(10, 10, 158, 112) +err := 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(). + Run() +``` + +# view + +function view generate [mermaid](https://mermaid-js.github.io/mermaid/#/) chart, which can be use in markdown or view [online](mermaid-js.github.io/mermaid-live-editor/) + +```go +split := Input(TestInputFile1).VFlip().Split() + split0, split1 := split.Get("0"), split.Get("1") + overlayFile := Input(TestOverlayFile).Crop(10, 10, 158, 112) +b, err := 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().View(ViewTypeFlowChart) +fmt.Println(b) +``` +![image](./docs/flowchart2.png) \ No newline at end of file diff --git a/docs/flowchart.png b/docs/flowchart.png new file mode 100644 index 0000000..f212b14 Binary files /dev/null and b/docs/flowchart.png differ diff --git a/docs/flowchart2.png b/docs/flowchart2.png new file mode 100644 index 0000000..497d7ce Binary files /dev/null and b/docs/flowchart2.png differ diff --git a/ffmpeg_test.go b/ffmpeg_test.go index 2634350..8de1791 100644 --- a/ffmpeg_test.go +++ b/ffmpeg_test.go @@ -278,3 +278,14 @@ func TestPipe(t *testing.T) { 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) +} diff --git a/view.go b/view.go new file mode 100644 index 0000000..0d9fbbe --- /dev/null +++ b/view.go @@ -0,0 +1,97 @@ +package ffmpeg_go + +import ( + "bytes" + "fmt" +) + +type ViewType string + +const ( + // FlowChart the diagram type for output in flowchart style (https://mermaid-js.github.io/mermaid/#/flowchart) (including current state + ViewTypeFlowChart ViewType = "flowChart" + // StateDiagram the diagram type for output in stateDiagram style (https://mermaid-js.github.io/mermaid/#/stateDiagram) + ViewTypeStateDiagram ViewType = "stateDiagram" +) + +func (s *Stream) View(viewType ViewType) (string, error) { + switch viewType { + case ViewTypeFlowChart: + return visualizeForMermaidAsFlowChart(s) + case ViewTypeStateDiagram: + return visualizeForMermaidAsStateDiagram(s) + default: + return "", fmt.Errorf("unknown ViewType: %s", viewType) + } +} + +func visualizeForMermaidAsStateDiagram(s *Stream) (string, error) { + var buf bytes.Buffer + + nodes := getStreamSpecNodes([]*Stream{s}) + var dagNodes []DagNode + for i := range nodes { + dagNodes = append(dagNodes, nodes[i]) + } + sorted, outGoingMap, err := TopSort(dagNodes) + if err != nil { + return "", err + } + + buf.WriteString("stateDiagram\n") + + for _, node := range sorted { + next := outGoingMap[node.Hash()] + for k, v := range next { + for _, nextNode := range v { + label := string(k) + if label == "" { + label = "<>" + } + buf.WriteString(fmt.Sprintf(` %s --> %s: %s`, node.ShortRepr(), nextNode.Node.ShortRepr(), label)) + buf.WriteString("\n") + } + } + } + return buf.String(), nil +} + +// visualizeForMermaidAsFlowChart outputs a visualization of a FSM in Mermaid format (including highlighting of current state). +func visualizeForMermaidAsFlowChart(s *Stream) (string, error) { + var buf bytes.Buffer + + nodes := getStreamSpecNodes([]*Stream{s}) + var dagNodes []DagNode + for i := range nodes { + dagNodes = append(dagNodes, nodes[i]) + } + sorted, outGoingMap, err := TopSort(dagNodes) + if err != nil { + return "", err + } + buf.WriteString("graph LR\n") + + for _, node := range sorted { + buf.WriteString(fmt.Sprintf(` %d[%s]`, node.Hash(), node.ShortRepr())) + buf.WriteString("\n") + } + buf.WriteString("\n") + + for _, node := range sorted { + next := outGoingMap[node.Hash()] + for k, v := range next { + for _, nextNode := range v { + label := string(k) + if label == "" { + label = "<>" + } + buf.WriteString(fmt.Sprintf(` %d --> |%s| %d`, node.Hash(), label, nextNode.Node.Hash())) + buf.WriteString("\n") + } + } + } + + buf.WriteString("\n") + + return buf.String(), nil +}