视频剪辑和处理

This commit is contained in:
lmk
2026-06-22 09:18:45 +08:00
parent 9bc48060dc
commit 7d4ac82334
34 changed files with 3319 additions and 839 deletions
+39
View File
@@ -0,0 +1,39 @@
package video
import (
"context"
"fmt"
dto "media/model/dto/video"
service "media/service/video"
"github.com/gogf/gf/v2/frame/g"
)
type caption struct{}
var Caption = new(caption)
// CreateCaption 创建字幕叠加任务 POST /video/caption
func (c *caption) CreateCaption(ctx context.Context, req *dto.CreateCaptionTaskReq) (res *dto.CreateCaptionTaskRes, err error) {
ctx = withUser(ctx)
g.Log().Infof(ctx, "[字幕叠加] 收到请求 入参: video_count=%d, element_count=%d, callback=%s",
len(req.VideoURLs), len(req.Elements), req.CallbackURL)
if len(req.VideoURLs) < 1 {
return nil, fmt.Errorf("至少需要1个视频")
}
taskID, taskErr := service.Caption.CreateAsyncTask(ctx, req.VideoURLs, req.AudioURL, req.Subtitles, req.SubtitleStyle, req.Elements, req.CallbackURL)
if taskErr != nil {
return nil, taskErr
}
return &dto.CreateCaptionTaskRes{TaskID: taskID}, nil
}
// GetCaptionTask 查询字幕任务结果 GET /video/caption/{taskId}
func (c *caption) GetCaptionTask(ctx context.Context, req *dto.GetCaptionTaskReq) (res *dto.GetCaptionTaskRes, err error) {
ctx = withUser(ctx)
return service.Caption.GetTaskResult(ctx, req.TaskID)
}
+42
View File
@@ -0,0 +1,42 @@
package video
import (
"context"
"fmt"
dto "media/model/dto/video"
service "media/service/video"
"github.com/gogf/gf/v2/frame/g"
)
type merge struct{}
var Merge = new(merge)
// MergeAsync 视频拼接+混音(异步) POST /video/merge/async
func (c *merge) MergeAsync(ctx context.Context, req *dto.VideoAudioMergeAsyncReq) (res *dto.CreateMergeTaskRes, err error) {
ctx = withUser(ctx)
g.Log().Infof(ctx, "[视频拼接+混音-异步] 收到请求 入参: video_count=%d, audio_count=%d, upload=%v, callback=%s",
len(req.VideoURLs), len(req.AudioURLs), req.Upload, req.CallbackURL)
if len(req.VideoURLs) < 1 {
return nil, fmt.Errorf("至少需要1个视频")
}
if len(req.AudioURLs) < 1 {
return nil, fmt.Errorf("至少需要1个音频")
}
taskID, taskErr := service.Merge.CreateAsyncTask(ctx, req.VideoURLs, req.AudioURLs, req.CallbackURL, req.Upload)
if taskErr != nil {
return nil, taskErr
}
return &dto.CreateMergeTaskRes{TaskID: taskID}, nil
}
// GetMergeTask 查询异步拼接+混音任务结果 GET /video/merge/task/{taskId}
func (c *merge) GetMergeTask(ctx context.Context, req *dto.GetMergeTaskReq) (res *dto.GetMergeTaskRes, err error) {
ctx = withUser(ctx)
return service.Merge.GetTaskResult(ctx, req.TaskID)
}
@@ -0,0 +1,39 @@
package video
import (
"context"
"fmt"
dto "media/model/dto/video"
service "media/service/video"
"github.com/gogf/gf/v2/frame/g"
)
type sceneSplit struct{}
var SceneSplit = new(sceneSplit)
// CreateSceneSplit 创建场景分割任务 POST /video/scene-split
func (c *sceneSplit) CreateSceneSplit(ctx context.Context, req *dto.SceneSplitReq) (res *dto.CreateSceneSplitTaskRes, err error) {
ctx = withUser(ctx)
g.Log().Infof(ctx, "[场景分割] 收到请求 入参: videoUrl=%s, threshold=%.1f, callback=%s",
req.VideoURL, req.Threshold, req.CallbackURL)
if req.VideoURL == "" {
return nil, fmt.Errorf("视频URL不能为空")
}
taskID, taskErr := service.SceneSplit.CreateAsyncTask(ctx, req.VideoURL, req.Threshold, req.CallbackURL)
if taskErr != nil {
return nil, taskErr
}
return &dto.CreateSceneSplitTaskRes{TaskID: taskID}, nil
}
// GetSceneSplitTask 查询场景分割任务结果 GET /video/scene-split/task/{taskId}
func (c *sceneSplit) GetSceneSplitTask(ctx context.Context, req *dto.GetSceneSplitTaskReq) (res *dto.GetSceneSplitTaskRes, err error) {
ctx = withUser(ctx)
return service.SceneSplit.GetTaskResult(ctx, req.TaskID)
}
+42
View File
@@ -0,0 +1,42 @@
package video
import (
"context"
"fmt"
dto "media/model/dto/video"
service "media/service/video"
commonController "media/controller/common"
"github.com/gogf/gf/v2/frame/g"
)
type transcode struct{}
var Transcode = new(transcode)
// Transcode 上传视频并转码为 H.264+AAC+MP4(faststart) POST /video/transcode
func (c *transcode) Transcode(ctx context.Context, req *struct {
g.Meta `path:"/video/transcode" method:"post" tags:"视频转码" summary:"上传视频转码为H.264+AAC+MP4(faststart)" dc:"上传视频文件,转码为标准MP4格式"`
OutputDir string `json:"outputDir" dc:"输出目录(可选),不传则输出到resource/temp下"`
}) (res *dto.TranscodeRes, err error) {
ctx = withUser(ctx)
// 保存上传文件
filePaths, saveErr := commonController.SaveUploadedFilesFromCtx(ctx)
if saveErr != nil || len(filePaths) == 0 {
return nil, fmt.Errorf("上传文件失败: %v", saveErr)
}
inputPath := filePaths[0]
g.Log().Infof(ctx, "[转码] 上传文件保存到: %s", inputPath)
// 调用转码服务,outputDir 为空则 service 用默认值
res, err = service.Transcode.TranscodeToMP4(ctx, inputPath, req.OutputDir)
if err != nil {
return nil, fmt.Errorf("转码失败: %v", err)
}
g.Log().Infof(ctx, "[转码] 完成: %s", res.OutputPath)
return res, nil
}