From 387b74b62e9eb357ecca1aa31008830a37edbf4b Mon Sep 17 00:00:00 2001 From: Justyer <1554694323@qq.com> Date: Thu, 12 Jun 2025 11:47:19 +0800 Subject: [PATCH] feat: snapshot frame_type add 2 --- examples/ffmpeg/amix/main.go | 41 +++++++++++++++++++++++++++++++ examples/ffmpeg/concat/main.go | 2 +- examples/service/snapshot/main.go | 5 ++-- ffmpeg/ffmpeg.go | 11 ++++----- snapshot.go | 16 ++++++++++-- snapshot_params.go | 22 +++++++++++------ 6 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 examples/ffmpeg/amix/main.go diff --git a/examples/ffmpeg/amix/main.go b/examples/ffmpeg/amix/main.go new file mode 100644 index 0000000..27b1ffc --- /dev/null +++ b/examples/ffmpeg/amix/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "context" + "fmt" + + "github.com/fxkt-tech/liv/ffmpeg" + "github.com/fxkt-tech/liv/ffmpeg/codec" + "github.com/fxkt-tech/liv/ffmpeg/filter" + "github.com/fxkt-tech/liv/ffmpeg/input" + "github.com/fxkt-tech/liv/ffmpeg/output" +) + +func main() { + var ( + ctx = context.Background() + input1 = input.WithSimple("a1.aac") + input2 = input.WithSimple("a2.aac") + fAmix = filter.AMix(2) + ) + + err := ffmpeg.New( + ffmpeg.WithLogLevel(""), + ffmpeg.WithDebug(true), + ffmpeg.WithDry(true), + ).AddInput( + input1, input2, + ).AddFilter( + fAmix, + ). + AddOutput( + output.New( + output.Map(fAmix), + output.AudioCodec(codec.AAC), + output.File("out.mp4"), + ), + ).Run(ctx) + if err != nil { + fmt.Println(err) + } +} diff --git a/examples/ffmpeg/concat/main.go b/examples/ffmpeg/concat/main.go index 6586b5d..9ecb102 100644 --- a/examples/ffmpeg/concat/main.go +++ b/examples/ffmpeg/concat/main.go @@ -19,7 +19,7 @@ func main() { err := ffmpeg.New( ffmpeg.WithLogLevel(""), ffmpeg.WithDebug(true), - // ffmpeg.Dry(true), + ffmpeg.WithDry(true), ).AddInput( input1, ).AddOutput( diff --git a/examples/service/snapshot/main.go b/examples/service/snapshot/main.go index abe4a33..c5ac9ff 100644 --- a/examples/service/snapshot/main.go +++ b/examples/service/snapshot/main.go @@ -15,8 +15,9 @@ func main() { Infile: "../../testdata/in.mp4", Outfile: "ss/simple-%05d.jpg", StartTime: 0, - // FrameType: 1, - Num: 4, + FrameType: 2, + Frames: []int32{1, 10, 300, 301}, + // Num: 4, // Interval: 5, Width: 960, Height: 540, diff --git a/ffmpeg/ffmpeg.go b/ffmpeg/ffmpeg.go index 9883b95..aa24f24 100644 --- a/ffmpeg/ffmpeg.go +++ b/ffmpeg/ffmpeg.go @@ -82,14 +82,13 @@ func (ff *FFmpeg) DryRun() { } func (ff *FFmpeg) Run(ctx context.Context) (err error) { - if ff.debug { + if ff.dry { + ff.DryRun() + return nil + } else if ff.debug { ff.DryRun() - } else { - if ff.dry { - ff.DryRun() - return nil - } } + cc := exec.CommandContext(ctx, ff.bin, ff.Params()...) retbytes, err := cc.CombinedOutput() if err != nil { diff --git a/snapshot.go b/snapshot.go index 4fe77a2..a56bed9 100644 --- a/snapshot.go +++ b/snapshot.go @@ -17,6 +17,7 @@ import ( "github.com/fxkt-tech/liv/ffmpeg/stream" "github.com/fxkt-tech/liv/ffprobe" "github.com/fxkt-tech/liv/pkg/math" + "github.com/fxkt-tech/liv/pkg/sugar" ) type Snapshot struct { @@ -54,12 +55,12 @@ func (ss *Snapshot) Simple(ctx context.Context, params *SnapshotParams) error { lastFilter := stream.V(0) // 使用普通帧截图时,必须要传截图间隔,除非只截一张 switch params.FrameType { - case 0: // 关键帧 + case 0: // 仅关键帧截图 selectFilter := filter.Select("'eq(pict_type,I)'") filters = append(filters, selectFilter) lastFilter = selectFilter outputOptions = append(outputOptions, output.VSync("vfr")) - case 1: + case 1: // 等间隔截图 if params.Num != 1 { if params.IntervalFrames > 0 { selectFilter := filter.Select(fmt.Sprintf("'not(mod(n,%d))'", params.IntervalFrames)) @@ -72,6 +73,17 @@ func (ss *Snapshot) Simple(ctx context.Context, params *SnapshotParams) error { lastFilter = fpsFilter } } + case 2: // 指定帧序列截图 + if len(params.Frames) > 0 { + selectExpr := fmt.Sprintf("'%s'", + strings.Join(sugar.Map(params.Frames, func(frame int32) string { + return fmt.Sprintf("eq(n,%d)", frame) + }), "+")) + selectFilter := filter.Select(selectExpr) + filters = append(filters, selectFilter) + lastFilter = selectFilter + outputOptions = append(outputOptions, output.VSync("vfr")) + } } if params.Width > 0 || params.Height > 0 { scaleFilter := filter.Scale(params.Width, params.Height).Use(lastFilter) diff --git a/snapshot_params.go b/snapshot_params.go index d207f4a..2fad771 100644 --- a/snapshot_params.go +++ b/snapshot_params.go @@ -1,15 +1,23 @@ package liv type SnapshotParams struct { - Infile string - Outfile string - StartTime float32 + Infile string + Outfile string + + // 0-仅关键帧截图 1-等间隔截图 2-指定帧序列截图 + FrameType int32 // 截图类型 + + // 等间隔截图 Interval int32 // 间隔时间 IntervalFrames int32 // 间隔帧数 - Num int32 - FrameType int32 // 0-仅关键帧 1-指定时间点的帧 - Width int32 - Height int32 + + // 指定帧序列截图 + Frames []int32 // 帧序列 + + StartTime float32 // 截图开始时间。截图类型为指定帧序列截图时不建议使用此参数 + Num int32 // 截图最大数量 + Width int32 + Height int32 } type SpriteParams struct {