1 Star 0 Fork 0

kaylee595 / go-wav2lipEx

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
ffmpeg.go 3.88 KB
一键复制 编辑 原始数据 按行查看 历史
kaylee595 提交于 2023-12-15 15:12 . first
package ffmpeg
import (
"bytes"
"context"
"fmt"
"github.com/spf13/cast"
"image"
"io"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
)
type Exec struct {
ffmpegFile string
Loglevel Loglevel
}
type Option func(*Exec)
func WithLoglevel(loglevel Loglevel) Option {
return func(e *Exec) {
e.Loglevel = loglevel
}
}
func New(ffmpegFile string, options ...Option) *Exec {
abs, _ := filepath.Abs(ffmpegFile)
e := &Exec{
ffmpegFile: abs,
Loglevel: LogLevelInfo,
}
for _, option := range options {
option(e)
}
return e
}
func (e *Exec) ExecCtx(ctx context.Context, args ...string) error {
_, err := e.ExecCtxValue(ctx, e.Loglevel, args...)
return err
}
func (e *Exec) ExecCtxValue(ctx context.Context, loglevel Loglevel, args ...string) (string, error) {
args = append(args, "-loglevel", cast.ToString(int(loglevel)))
cmd := exec.CommandContext(ctx, e.ffmpegFile, args...)
errContext := new(bytes.Buffer)
cmd.Stderr = io.MultiWriter(errContext, os.Stderr)
cmd.Stdout = io.MultiWriter(errContext, os.Stdout)
err := cmd.Run()
if err != nil {
err = fmt.Errorf("cmd: [ %s ]\n%s\n\n%s", cmd.String(), errContext.String(), err.Error())
}
return errContext.String(), err
}
// VideoFrameExtraction 将视频以每秒24帧的方式提取
// videoFile 视频文件
// outputDir 输出目录
func (e *Exec) VideoFrameExtraction(ctx context.Context, videoFile, outputDir string) error {
args := []string{
"-i", videoFile,
"-vf", "fps=24",
"-f", "image2",
"-y",
filepath.Join(outputDir, "%013d.png"),
}
return e.ExecCtx(ctx, args...)
}
// MergeImg2Video 合并图片成视频
func (e *Exec) MergeImg2Video(ctx context.Context, imgDir, audioFile, outputFile string) error {
args := []string{
"-y",
"-r", "24",
"-i", filepath.Join(imgDir, "%013d.png"),
"-i", audioFile,
"-vcodec", "libx264",
"-c:a", "aac",
"-crf", "20",
"-preset", "slow",
"-movflags", "faststart",
"-vf", "format=yuv420p",
outputFile,
}
return e.ExecCtx(ctx, args...)
}
// Overlay 视频叠加
func (e *Exec) Overlay(ctx context.Context, isVideo bool, outputFile string, elementFile ...string) error {
var args []string
var filterComplexOverlay string
for index, item := range elementFile {
args = append(args, "-i", item)
filterComplexOverlay += fmt.Sprintf("[%d:v]", index)
}
args = append(args,
"-filter_complex", filterComplexOverlay+"overlay",
"-crf", "18",
)
if isVideo {
args = append(args,
"-codec:a", "copy",
"-c:v", "libx264",
)
}
args = append(args, "-y", outputFile)
return e.ExecCtx(ctx, args...)
}
// GenerateVideoPreviewImg 视频预览图
func (e *Exec) GenerateVideoPreviewImg(ctx context.Context, videoFilePath, outputFilePath string) error {
args := []string{
"-i", videoFilePath,
"-vf", "select=eq(n\\,0)",
"-vframes", "1",
outputFilePath,
}
return e.ExecCtx(ctx, args...)
}
// Scale 缩放
func (e *Exec) Scale(ctx context.Context, input string, w, h int, output string) error {
args := []string{
"-i", input,
"-vf", fmt.Sprintf("scale=%d:%d", w, h),
output,
}
return e.ExecCtx(ctx, args...)
}
// GetResolution 获取分辨率
func (e *Exec) GetResolution(ctx context.Context, input string) (image.Point, error) {
var p image.Point
// 这里绝对是会出错的, 就算获取到了分辨率, 这里不判断错误, 让后面获取不到实际分辨率再将这里的错误返回出去
info, err := e.ExecCtxValue(ctx, LogLevelInfo, "-i", input)
var resolutionLine string
for _, line := range strings.Split(info, "\n") {
if strings.Contains(line, "Stream #0:0") && strings.Contains(line, "Video:") {
resolutionLine = line
break
}
}
re := regexp.MustCompile(`\w[1-9]\d*x[1-9]\d+\w`)
match := re.FindStringSubmatch(resolutionLine)
if len(match) > 0 {
splits := strings.Split(match[0], "x")
if len(splits) > 1 {
p.X = cast.ToInt(splits[0])
p.Y = cast.ToInt(splits[1])
}
}
if p.X == 0 || p.Y == 0 {
return p, err
}
return p, nil
}
1
https://gitee.com/kaylee595/go-wav2lipEx.git
git@gitee.com:kaylee595/go-wav2lipEx.git
kaylee595
go-wav2lipEx
go-wav2lipEx
v1.1.2

搜索帮助

53164aa7 5694891 3bd8fe86 5694891