From f7cd004f847df6636d2ea23ede4d7a4bc8b52a4e Mon Sep 17 00:00:00 2001 From: Justyer <1554694323@qq.com> Date: Fri, 8 Dec 2023 00:09:39 +0800 Subject: [PATCH] feat: concat service --- examples/service/transcode/concat/main.go | 35 +++++++++++++++++ go.mod | 2 +- go.sum | 4 +- internal/sugar/mapper.go | 46 +++++++++++++++++++++++ transcode.go | 42 +++++++++++++++++++++ transcode_params.go | 7 ++++ transcode_spec.go | 8 ++++ 7 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 examples/service/transcode/concat/main.go create mode 100644 internal/sugar/mapper.go diff --git a/examples/service/transcode/concat/main.go b/examples/service/transcode/concat/main.go new file mode 100644 index 0000000..fb3fc03 --- /dev/null +++ b/examples/service/transcode/concat/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "context" + "fmt" + + "github.com/fxkt-tech/liv" + "github.com/fxkt-tech/liv/ffmpeg" +) + +func main() { + var ( + ctx = context.Background() + params = &liv.ConcatParams{ + Infiles: []string{ + "../../../testdata/in1.mp4", + "../../../testdata/in2.mp4", + }, + ConcatFile: "mylist.txt", + Outfile: "out.mp4", + } + ) + + tc := liv.NewTranscode( + liv.FFmpegOptions( + ffmpeg.Binary("ffmpeg"), + ffmpeg.Debug(true), + // ffmpeg.Dry(true), + ), + ) + err := tc.Concat(ctx, params) + if err != nil { + fmt.Println(err) + } +} diff --git a/go.mod b/go.mod index 74bedb9..4193555 100644 --- a/go.mod +++ b/go.mod @@ -4,5 +4,5 @@ go 1.21 require ( github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e + golang.org/x/exp v0.0.0-20231006140011-7918f672742d ) diff --git a/go.sum b/go.sum index 65809e4..68b1aa2 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= diff --git a/internal/sugar/mapper.go b/internal/sugar/mapper.go new file mode 100644 index 0000000..b375559 --- /dev/null +++ b/internal/sugar/mapper.go @@ -0,0 +1,46 @@ +package sugar + +type Single[I, O any] func(I) O + +func Range[I, O any](inS []I, f Single[I, O]) []O { + outs := make([]O, len(inS)) + for i, in := range inS { + outs[i] = f(in) + } + return outs +} + +func In[T int | string](elems []T, dest T) bool { + for _, elem := range elems { + if elem == dest { + return true + } + } + return false +} + +func If[F func()](cond bool, f F) { + if cond { + f() + } +} + +func Filter[T any](slices []T, satisfied func(T) bool) []T { + var results []T + for _, s := range slices { + if satisfied(s) { + results = append(results, s) + } + } + return results +} + +func MapTo[T1, T2 any](slices []T1, deal func(T1) (T2, error)) []T2 { + var results []T2 + for _, s := range slices { + if t, err := deal(s); err == nil { + results = append(results, t) + } + } + return results +} diff --git a/transcode.go b/transcode.go index 04ca74d..ec87399 100644 --- a/transcode.go +++ b/transcode.go @@ -3,6 +3,8 @@ package liv import ( "context" "fmt" + "os" + "strings" "github.com/fxkt-tech/liv/ffmpeg" "github.com/fxkt-tech/liv/ffmpeg/codec" @@ -11,6 +13,7 @@ import ( "github.com/fxkt-tech/liv/ffmpeg/naming" "github.com/fxkt-tech/liv/ffmpeg/output" "github.com/fxkt-tech/liv/ffmpeg/util" + "github.com/fxkt-tech/liv/internal/sugar" ) type Transcode struct { @@ -284,6 +287,7 @@ func (tc *Transcode) ConvertContainer(ctx context.Context, params *ConvertContai Run(ctx) } +// 转hls func (tc *Transcode) SimpleHLS(ctx context.Context, params *TranscodeSimpleHLSParams) error { err := tc.spec.SimpleHLSSatified(params) if err != nil { @@ -385,6 +389,7 @@ func (tc *Transcode) SimpleHLS(ctx context.Context, params *TranscodeSimpleHLSPa Run(ctx) } +// 转ts func (tc *Transcode) SimpleTS(ctx context.Context, params *TranscodeSimpleTSParams) error { err := tc.spec.SimpleTSSatified(params) if err != nil { @@ -498,6 +503,43 @@ func (tc *Transcode) SimpleTS(ctx context.Context, params *TranscodeSimpleTSPara Run(ctx) } +func concatFile(files []string, localPath string) error { + f, err := os.Create(localPath) + if err != nil { + return err + } + files = sugar.Range(files, func(f string) string { return fmt.Sprintf("file %s", f) }) + fs := strings.Join(files, "\n") + _, err = f.Write([]byte(fs)) + return err +} + +// 多个视频合并成一个 +func (tc *Transcode) Concat(ctx context.Context, params *ConcatParams) error { + err := tc.spec.ConcatSatified(params) + if err != nil { + return err + } + + err = concatFile(params.Infiles, params.ConcatFile) + if err != nil { + return err + } + + return ffmpeg.NewFFmpeg( + ffmpeg.Debug(true), + ).AddInput( + input.WithConcat(params.ConcatFile), + ).AddOutput( + output.New( + output.VideoCodec(codec.Copy), + output.AudioCodec(codec.Copy), + output.Duration(params.Duration), + output.File(params.Outfile), + ), + ).Run(ctx) +} + // ffmpeg -i in.mp4 -vn -c:a copy out.aac func (tc *Transcode) ExtractAudio(ctx context.Context, params *ExtractAudioParams) error { err := tc.spec.ExtractAudioSatified(params) diff --git a/transcode_params.go b/transcode_params.go index 8130a14..8fd64ea 100644 --- a/transcode_params.go +++ b/transcode_params.go @@ -30,6 +30,13 @@ type TranscodeSimpleHLSParams struct { Threads int32 } +type ConcatParams struct { + Infiles []string + ConcatFile string // eg. mylist.txt + Outfile string + Duration float64 +} + type ExtractAudioParams struct { Infile string Outfile string diff --git a/transcode_spec.go b/transcode_spec.go index d4f399b..e9772d3 100644 --- a/transcode_spec.go +++ b/transcode_spec.go @@ -52,6 +52,14 @@ func (*TranscodeSpec) SimpleTSSatified(params *TranscodeSimpleTSParams) error { return nil } +func (*TranscodeSpec) ConcatSatified(params *ConcatParams) error { + if params == nil || len(params.Infiles) == 0 || params.Outfile == "" { + return ErrParamsInvalid + } + + return nil +} + func (*TranscodeSpec) ExtractAudioSatified(params *ExtractAudioParams) error { if params == nil || params.Infile == "" || params.Outfile == "" { return ErrParamsInvalid