mirror of
https://github.com/u2takey/ffmpeg-go.git
synced 2025-10-05 07:56:51 +08:00
add example; add escape
move sample data
This commit is contained in:
23
examples/example_test.go
Normal file
23
examples/example_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package examples
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
)
|
||||
|
||||
func TestExampleStream(t *testing.T) {
|
||||
ExampleStream("./sample_data/in1.mp4", "./sample_data/out1.mp4", false)
|
||||
}
|
||||
|
||||
func TestExampleReadFramAsJpeg(t *testing.T) {
|
||||
reader := ExampleReadFrameAsJpeg("./sample_data/in1.mp4", 5)
|
||||
img, err := imaging.Decode(reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = imaging.Save(img, "./sample_data/out1.jpeg")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
@@ -4,4 +4,7 @@ go 1.14
|
||||
|
||||
replace github.com/u2takey/ffmpeg-go => ../../ffmpeg-go
|
||||
|
||||
require github.com/u2takey/ffmpeg-go v0.0.0-00010101000000-000000000000
|
||||
require (
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/u2takey/ffmpeg-go v0.0.0-00010101000000-000000000000
|
||||
)
|
||||
|
@@ -1,6 +1,8 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
@@ -30,6 +32,8 @@ github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
|
||||
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/u2takey/go-utils v0.0.0-20200713025200-4704d09fc2c7 h1:PT7mE8HJE1mwaSazrOdSeByJ1FoV33/fHUZrBB+zwVU=
|
||||
github.com/u2takey/go-utils v0.0.0-20200713025200-4704d09fc2c7/go.mod h1:ATqKFpgjUIlhGRs8j59gXmu8Cmpo1QQEHV6vwu1hs28=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
23
examples/readFrameAsJpeg.go
Normal file
23
examples/readFrameAsJpeg.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package examples
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
ffmpeg "github.com/u2takey/ffmpeg-go"
|
||||
)
|
||||
|
||||
func ExampleReadFrameAsJpeg(inFileName string, frameNum int) io.Reader {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := ffmpeg.Input(inFileName).
|
||||
Filter("select", ffmpeg.Args{fmt.Sprintf("gte(n,%d)", frameNum)}).
|
||||
Output("pipe:", ffmpeg.KwArgs{"vframes": 1, "format": "image2", "vcodec": "mjpeg"}).
|
||||
WithOutput(buf, os.Stdout).
|
||||
Run()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return buf
|
||||
}
|
BIN
examples/sample_data/out1.jpeg
Normal file
BIN
examples/sample_data/out1.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -1,41 +1,14 @@
|
||||
package main
|
||||
package examples
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
ffmpeg "github.com/u2takey/ffmpeg-go"
|
||||
)
|
||||
|
||||
var (
|
||||
InputFile = flag.String("in_filename", "./in1.mp4", "Input filename")
|
||||
OutputFile = flag.String("out_filename", "./out.mp4", "Input filename")
|
||||
Dream = flag.Bool("dream", false, "Use DeepDream frame processing (requires tensorflow)")
|
||||
)
|
||||
|
||||
// Buffer is a goroutine safe bytes.Buffer
|
||||
type Buffer struct {
|
||||
buffer bytes.Buffer
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (s *Buffer) Write(p []byte) (n int, err error) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
return s.buffer.Write(p)
|
||||
}
|
||||
|
||||
func (s *Buffer) Read(p []byte) (n int, err error) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
return s.buffer.Read(p)
|
||||
}
|
||||
|
||||
func getVideoSize(fileName string) (int, int) {
|
||||
log.Println("Getting video size for", fileName)
|
||||
data, err := ffmpeg.Probe(fileName)
|
||||
@@ -125,7 +98,7 @@ func process(reader io.ReadCloser, writer io.WriteCloser, w, h int) {
|
||||
return
|
||||
}
|
||||
|
||||
func run(inFile, outFile string) {
|
||||
func runExampleStream(inFile, outFile string) {
|
||||
w, h := getVideoSize(inFile)
|
||||
log.Println(w, h)
|
||||
|
||||
@@ -145,11 +118,20 @@ func run(inFile, outFile string) {
|
||||
log.Println("Done")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if *Dream == true {
|
||||
fmt.Println("tensorflow mode not implemented, todo")
|
||||
return
|
||||
// ExampleStream
|
||||
// inFileName: input filename
|
||||
// outFileName: output filename
|
||||
// dream: Use DeepDream frame processing (requires tensorflow)
|
||||
func ExampleStream(inFileName, outFileName string, dream bool) {
|
||||
if inFileName == "" {
|
||||
inFileName = "./in1.mp4"
|
||||
}
|
||||
run(*InputFile, *OutputFile)
|
||||
if outFileName == "" {
|
||||
outFileName = "./out.mp4"
|
||||
}
|
||||
if dream {
|
||||
panic("Use DeepDream With Tensorflow haven't been implemented")
|
||||
}
|
||||
|
||||
runExampleStream(inFileName, outFileName)
|
||||
}
|
||||
|
@@ -9,6 +9,12 @@ import (
|
||||
"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")
|
||||
@@ -120,7 +126,7 @@ func TestFilterWithSelector(t *testing.T) {
|
||||
i := Input(TestInputFile1)
|
||||
|
||||
v1 := i.Video().HFlip()
|
||||
a1 := i.Audio().Filter("aecho", []string{"0.8", "0.9", "1000", "0.3"})
|
||||
a1 := i.Audio().Filter("aecho", Args{"0.8", "0.9", "1000", "0.3"})
|
||||
|
||||
out := Output([]*Stream{a1, v1}, TestOutputFile1)
|
||||
assert.Equal(t, []string{
|
||||
|
@@ -11,15 +11,15 @@ func AssetType(hasType, expectType string, action string) {
|
||||
}
|
||||
}
|
||||
|
||||
func FilterMultiOutput(streamSpec []*Stream, filterName string, args []string, kwArgs ...KwArgs) *Node {
|
||||
func FilterMultiOutput(streamSpec []*Stream, filterName string, args Args, kwArgs ...KwArgs) *Node {
|
||||
return NewFilterNode(filterName, streamSpec, -1, args, MergeKwArgs(kwArgs))
|
||||
}
|
||||
|
||||
func Filter(streamSpec []*Stream, filterName string, args []string, kwArgs ...KwArgs) *Stream {
|
||||
func Filter(streamSpec []*Stream, filterName string, args Args, kwArgs ...KwArgs) *Stream {
|
||||
return FilterMultiOutput(streamSpec, filterName, args, MergeKwArgs(kwArgs)).Stream("", "")
|
||||
}
|
||||
|
||||
func (s *Stream) Filter(filterName string, args []string, kwArgs ...KwArgs) *Stream {
|
||||
func (s *Stream) Filter(filterName string, args Args, kwArgs ...KwArgs) *Stream {
|
||||
AssetType(s.Type, "FilterableStream", "filter")
|
||||
return Filter([]*Stream{s}, filterName, args, MergeKwArgs(kwArgs))
|
||||
}
|
||||
|
1
go.mod
1
go.mod
@@ -3,6 +3,7 @@ module github.com/u2takey/ffmpeg-go
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/tidwall/gjson v1.6.3
|
||||
github.com/u2takey/go-utils v0.0.0-20200713025200-4704d09fc2c7
|
||||
|
4
go.sum
4
go.sum
@@ -1,6 +1,8 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
@@ -30,6 +32,8 @@ github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
|
||||
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/u2takey/go-utils v0.0.0-20200713025200-4704d09fc2c7 h1:PT7mE8HJE1mwaSazrOdSeByJ1FoV33/fHUZrBB+zwVU=
|
||||
github.com/u2takey/go-utils v0.0.0-20200713025200-4704d09fc2c7/go.mod h1:ATqKFpgjUIlhGRs8j59gXmu8Cmpo1QQEHV6vwu1hs28=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
12
node.go
12
node.go
@@ -248,13 +248,12 @@ func (n *Node) GetFilter(outgoingEdges []DagEdge) string {
|
||||
if n.nodeType != "FilterNode" {
|
||||
panic("call GetFilter on non-FilterNode")
|
||||
}
|
||||
args := n.args
|
||||
kwargs := n.kwargs
|
||||
args, kwargs, ret := n.args, n.kwargs, ""
|
||||
if n.name == "split" || n.name == "asplit" {
|
||||
args = []string{fmt.Sprintf("%d", len(outgoingEdges))}
|
||||
}
|
||||
// todo escape char
|
||||
for _, k := range kwargs.SortedKeys() {
|
||||
args = Args(args).EscapeWith("\\'=:")
|
||||
for _, k := range kwargs.EscapeWith("\\'=:").SortedKeys() {
|
||||
v := getString(kwargs[k])
|
||||
if v != "" {
|
||||
args = append(args, fmt.Sprintf("%s=%s", k, v))
|
||||
@@ -262,8 +261,9 @@ func (n *Node) GetFilter(outgoingEdges []DagEdge) string {
|
||||
args = append(args, fmt.Sprintf("%s", k))
|
||||
}
|
||||
}
|
||||
ret = escapeChars(n.name, "\\'=:")
|
||||
if len(args) > 0 {
|
||||
return fmt.Sprintf("%s=%s", n.name, strings.Join(args, ":"))
|
||||
ret += fmt.Sprintf("=%s", strings.Join(args, ":"))
|
||||
}
|
||||
return fmt.Sprintf("%s", n.name)
|
||||
return escapeChars(ret, "\\'[],;")
|
||||
}
|
||||
|
@@ -7,12 +7,6 @@ import (
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
const (
|
||||
TestInputFile1 = "./sample_data/in1.mp4"
|
||||
TestOutputFile1 = "./sample_data/out1.mp4"
|
||||
TestOverlayFile = "./sample_data/overlay.png"
|
||||
)
|
||||
|
||||
func TestProbe(t *testing.T) {
|
||||
data, err := Probe(TestInputFile1, nil)
|
||||
assert.Nil(t, err)
|
||||
|
2
run.go
2
run.go
@@ -57,8 +57,6 @@ func _getFilterSpec(node *Node, outOutingEdgeMap map[Label][]NodeInfo, streamNam
|
||||
for _, e := range outEdges {
|
||||
output = append(output, formatOutStreamName(streamNameMap, e))
|
||||
}
|
||||
//sort.Strings(input)
|
||||
//sort.Strings(output)
|
||||
return fmt.Sprintf("%s%s%s", strings.Join(input, ""), node.GetFilter(outEdges), strings.Join(output, ""))
|
||||
}
|
||||
|
||||
|
Binary file not shown.
53
utils.go
53
utils.go
@@ -6,6 +6,8 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/u2takey/go-utils/sets"
|
||||
)
|
||||
|
||||
func getString(item interface{}) string {
|
||||
@@ -17,6 +19,8 @@ func getString(item interface{}) string {
|
||||
return a
|
||||
case []string:
|
||||
return strings.Join(a, ", ")
|
||||
case Args:
|
||||
return strings.Join(a, ", ")
|
||||
case []interface{}:
|
||||
var r []string
|
||||
for _, b := range a {
|
||||
@@ -76,17 +80,36 @@ func getHash(item interface{}) int {
|
||||
}
|
||||
}
|
||||
|
||||
//def escape_chars(text, chars):
|
||||
// """Helper function to escape uncomfortable characters."""
|
||||
// text = str(text)
|
||||
// chars = list(set(chars))
|
||||
// if '\\' in chars:
|
||||
// chars.remove('\\')
|
||||
// chars.insert(0, '\\')
|
||||
// for ch in chars:
|
||||
// text = text.replace(ch, '\\' + ch)
|
||||
// return text
|
||||
//
|
||||
func escapeChars(text, chars string) string {
|
||||
s := sets.NewString()
|
||||
for _, a := range chars {
|
||||
s.Insert(string(a))
|
||||
}
|
||||
sl := s.List()
|
||||
if s.Has("\\") {
|
||||
s.Delete("\\")
|
||||
sl = append([]string{"\\"}, s.List()...)
|
||||
}
|
||||
for _, ch := range sl {
|
||||
text = strings.ReplaceAll(text, ch, "\\"+ch)
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
type Args []string
|
||||
|
||||
func (a Args) Sorted() Args {
|
||||
sort.Strings(a)
|
||||
return a
|
||||
}
|
||||
|
||||
func (a Args) EscapeWith(chars string) Args {
|
||||
out := Args{}
|
||||
for _, b := range a {
|
||||
out = append(out, escapeChars(b, chars))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type KwArgs map[string]interface{}
|
||||
|
||||
@@ -100,6 +123,14 @@ func MergeKwArgs(args []KwArgs) KwArgs {
|
||||
return a
|
||||
}
|
||||
|
||||
func (a KwArgs) EscapeWith(chars string) KwArgs {
|
||||
out := KwArgs{}
|
||||
for k, v := range a {
|
||||
out[escapeChars(k, chars)] = escapeChars(getString(v), chars)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (a KwArgs) Copy() KwArgs {
|
||||
r := KwArgs{}
|
||||
for k := range a {
|
||||
|
Reference in New Issue
Block a user