feat: concat service

This commit is contained in:
Justyer
2023-12-08 00:09:39 +08:00
parent 3212d1b93a
commit f7cd004f84
7 changed files with 141 additions and 3 deletions

View File

@@ -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)
}
}

2
go.mod
View File

@@ -4,5 +4,5 @@ go 1.21
require ( require (
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b 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
) )

4
go.sum
View File

@@ -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-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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= 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/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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=

46
internal/sugar/mapper.go Normal file
View File

@@ -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
}

View File

@@ -3,6 +3,8 @@ package liv
import ( import (
"context" "context"
"fmt" "fmt"
"os"
"strings"
"github.com/fxkt-tech/liv/ffmpeg" "github.com/fxkt-tech/liv/ffmpeg"
"github.com/fxkt-tech/liv/ffmpeg/codec" "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/naming"
"github.com/fxkt-tech/liv/ffmpeg/output" "github.com/fxkt-tech/liv/ffmpeg/output"
"github.com/fxkt-tech/liv/ffmpeg/util" "github.com/fxkt-tech/liv/ffmpeg/util"
"github.com/fxkt-tech/liv/internal/sugar"
) )
type Transcode struct { type Transcode struct {
@@ -284,6 +287,7 @@ func (tc *Transcode) ConvertContainer(ctx context.Context, params *ConvertContai
Run(ctx) Run(ctx)
} }
// 转hls
func (tc *Transcode) SimpleHLS(ctx context.Context, params *TranscodeSimpleHLSParams) error { func (tc *Transcode) SimpleHLS(ctx context.Context, params *TranscodeSimpleHLSParams) error {
err := tc.spec.SimpleHLSSatified(params) err := tc.spec.SimpleHLSSatified(params)
if err != nil { if err != nil {
@@ -385,6 +389,7 @@ func (tc *Transcode) SimpleHLS(ctx context.Context, params *TranscodeSimpleHLSPa
Run(ctx) Run(ctx)
} }
// 转ts
func (tc *Transcode) SimpleTS(ctx context.Context, params *TranscodeSimpleTSParams) error { func (tc *Transcode) SimpleTS(ctx context.Context, params *TranscodeSimpleTSParams) error {
err := tc.spec.SimpleTSSatified(params) err := tc.spec.SimpleTSSatified(params)
if err != nil { if err != nil {
@@ -498,6 +503,43 @@ func (tc *Transcode) SimpleTS(ctx context.Context, params *TranscodeSimpleTSPara
Run(ctx) 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 // ffmpeg -i in.mp4 -vn -c:a copy out.aac
func (tc *Transcode) ExtractAudio(ctx context.Context, params *ExtractAudioParams) error { func (tc *Transcode) ExtractAudio(ctx context.Context, params *ExtractAudioParams) error {
err := tc.spec.ExtractAudioSatified(params) err := tc.spec.ExtractAudioSatified(params)

View File

@@ -30,6 +30,13 @@ type TranscodeSimpleHLSParams struct {
Threads int32 Threads int32
} }
type ConcatParams struct {
Infiles []string
ConcatFile string // eg. mylist.txt
Outfile string
Duration float64
}
type ExtractAudioParams struct { type ExtractAudioParams struct {
Infile string Infile string
Outfile string Outfile string

View File

@@ -52,6 +52,14 @@ func (*TranscodeSpec) SimpleTSSatified(params *TranscodeSimpleTSParams) error {
return nil 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 { func (*TranscodeSpec) ExtractAudioSatified(params *ExtractAudioParams) error {
if params == nil || params.Infile == "" || params.Outfile == "" { if params == nil || params.Infile == "" || params.Outfile == "" {
return ErrParamsInvalid return ErrParamsInvalid