视频剪辑和处理
This commit is contained in:
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user