通过分镜json剪辑视频

This commit is contained in:
2026-05-25 15:08:47 +08:00
parent e79f8a6131
commit e6c27e2dee
9 changed files with 1046 additions and 1 deletions

View File

@@ -0,0 +1,78 @@
package video
import "github.com/gogf/gf/v2/frame/g"
// CutScene 单个分镜场景
// 同时兼容两种格式:
// 1. 完整格式: {"sceneIndex":1,"startTimeStr":"00:00:00.000","endTimeStr":"00:00:03.115", ...}
// 2. 简化格式: {"start": 1.5, "end": 5.0}
type CutScene struct {
SceneIndex int `json:"sceneIndex" dc:"场景序号"`
StartTimeStr string `json:"startTimeStr" dc:"起始时间 HH:MM:SS.mmm"`
EndTimeStr string `json:"endTimeStr" dc:"结束时间 HH:MM:SS.mmm"`
Start float64 `json:"start" dc:"起始时间(秒)"`
End float64 `json:"end" dc:"结束时间(秒)"`
DurationStr string `json:"durationStr" dc:"时长"`
ShotType string `json:"shotType" dc:"镜头类型"`
Composition string `json:"composition" dc:"构图"`
NarrativePos string `json:"narrativePos" dc:"叙事位置"`
Description string `json:"description" dc:"描述"`
}
// CutReq 视频分镜剪切请求URL 方式)
type CutReq struct {
g.Meta `path:"/video/cut" method:"post" tags:"视频剪切" summary:"视频分镜剪切(URL模式)" dc:"根据分镜JSON从视频中剪切多个片段并拼接输出"`
VideoURL string `json:"video_url" v:"required#视频URL不能为空" dc:"原始视频URL"`
Scenes []CutScene `json:"scenes" v:"required#分镜片段不能为空" dc:"分镜片段数组"`
TotalScenes int `json:"totalScenes" dc:"总分镜数"`
DurationStr string `json:"durationStr" dc:"总时长"`
Upload bool `json:"upload" dc:"是否上传到MinIO" d:"false"`
}
// CutAsyncReq 视频分镜剪切-异步请求URL方式
type CutAsyncReq struct {
g.Meta `path:"/video/cut/async" method:"post" tags:"视频剪切" summary:"视频分镜剪切-异步(URL模式)" dc:"异步根据分镜JSON剪切视频立即返回taskId完成后通过callback_url通知结果"`
VideoURL string `json:"video_url" v:"required#视频URL不能为空" dc:"原始视频URL"`
Scenes []CutScene `json:"scenes" v:"required#分镜片段不能为空" dc:"分镜片段数组"`
TotalScenes int `json:"totalScenes" dc:"总分镜数"`
DurationStr string `json:"durationStr" dc:"总时长"`
Upload bool `json:"upload" dc:"是否上传到MinIO" d:"false"`
CallbackURL string `json:"callback_url" v:"required#回调地址不能为空" dc:"回调地址剪切完成后POST结果到该地址"`
}
// CutRes 视频分镜剪切响应
type CutRes struct {
OutputPath string `json:"outputPath" dc:"输出文件路径"`
FileSize int64 `json:"fileSize" dc:"文件大小(字节)"`
Duration float64 `json:"duration" dc:"总时长(秒)"`
DurationStr string `json:"durationStr" dc:"可读时长"`
ShotsCount int `json:"shotsCount" dc:"输出片段数"`
FileURL string `json:"fileURL" dc:"MinIO访问地址上传后返回"`
}
// ---------- 异步剪切任务 ----------
// CreateCutTaskRes 创建异步剪切任务响应
type CreateCutTaskRes struct {
TaskID string `json:"taskId" dc:"任务ID"`
}
// GetCutTaskReq 查询异步剪切任务请求
type GetCutTaskReq struct {
g.Meta `path:"/video/cut/task/{taskId}" method:"get" tags:"视频剪切" summary:"查询剪切任务结果" dc:"根据taskId查询异步剪切任务的结果"`
TaskID string `json:"taskId" dc:"任务ID"`
}
// GetCutTaskRes 查询异步剪切任务响应
type GetCutTaskRes struct {
TaskID string `json:"taskId" dc:"任务ID"`
Status string `json:"status" dc:"状态: pending/running/success/failed"`
FileURL string `json:"fileURL,omitempty" dc:"MinIO文件访问路径"`
FileSize int64 `json:"fileSize,omitempty" dc:"文件大小(字节)"`
FileName string `json:"fileName,omitempty" dc:"文件名"`
FileFormat string `json:"fileFormat,omitempty" dc:"文件格式"`
FileAddressPrefix string `json:"fileAddressPrefix,omitempty" dc:"MinIO地址前缀"`
DurationStr string `json:"durationStr,omitempty" dc:"剪切后时长"`
ErrorMessage string `json:"errorMessage,omitempty" dc:"错误信息"`
CreatedAt int64 `json:"createdAt" dc:"创建时间戳"`
}

View File

@@ -0,0 +1,54 @@
package video
import "gitea.com/red-future/common/beans"
// CutTask 视频分镜剪切异步任务实体
type CutTask struct {
beans.SQLBaseDO `orm:",inherit"`
TaskID string `orm:"task_id" json:"taskId" description:"任务唯一标识"`
VideoURL string `orm:"video_url" json:"videoUrl" description:"原始视频URL"`
ShotsJSON string `orm:"shots_json" json:"shotsJson" description:"分镜JSON"`
Status string `orm:"status" json:"status" description:"任务状态:pending/running/success/failed"`
FileURL string `orm:"file_url" json:"fileUrl" description:"MinIO文件访问路径"`
FileSize int64 `orm:"file_size" json:"fileSize" description:"文件大小(字节)"`
FileName string `orm:"file_name" json:"fileName" description:"文件名"`
FileFormat string `orm:"file_format" json:"fileFormat" description:"文件格式"`
FileAddressPrefix string `orm:"file_address_prefix" json:"fileAddressPrefix" description:"MinIO地址前缀"`
DurationStr string `orm:"duration_str" json:"durationStr" description:"剪切后时长"`
ErrorMessage string `orm:"error_message" json:"errorMessage" description:"错误信息"`
CallbackURL string `orm:"callback_url" json:"callbackUrl" description:"回调地址"`
}
// CutTaskCol 字段定义
type CutTaskCol struct {
beans.SQLBaseCol
TaskID string
VideoURL string
ShotsJSON string
Status string
FileURL string
FileSize string
FileName string
FileFormat string
FileAddressPrefix string
DurationStr string
ErrorMessage string
CallbackURL string
}
// CutTaskCols 字段常量
var CutTaskCols = CutTaskCol{
SQLBaseCol: beans.DefSQLBaseCol,
TaskID: "task_id",
VideoURL: "video_url",
ShotsJSON: "shots_json",
Status: "status",
FileURL: "file_url",
FileSize: "file_size",
FileName: "file_name",
FileFormat: "file_format",
FileAddressPrefix: "file_address_prefix",
DurationStr: "duration_str",
ErrorMessage: "error_message",
CallbackURL: "callback_url",
}