添加视频帧提取功能和阿里云OSS存储支持
- 新增从视频素材提取首帧/尾帧的功能,支持画面连续性编辑 - 添加阿里云OSS存储支持,可配置本地或OSS存储方式 - 导入视频素材时自动探测并更新视频时长信息 - 前端添加从素材提取尾帧的UI界面 - 添加FramePrompt模型的数据库迁移 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
69
infrastructure/external/ffmpeg/ffmpeg.go
vendored
69
infrastructure/external/ffmpeg/ffmpeg.go
vendored
@@ -853,3 +853,72 @@ func (f *FFmpeg) generateSilence(outputPath string, duration float64) (string, e
|
||||
f.log.Infow("Silence audio generated successfully", "output", outputPath)
|
||||
return outputPath, nil
|
||||
}
|
||||
|
||||
// ExtractFrame 从视频中提取指定位置的帧
|
||||
// position: "first" 提取首帧, "last" 提取尾帧
|
||||
// 返回提取的图片文件路径
|
||||
func (f *FFmpeg) ExtractFrame(videoURL, outputPath, position string) (string, error) {
|
||||
f.log.Infow("Extracting frame from video", "url", videoURL, "position", position, "output", outputPath)
|
||||
|
||||
// 下载视频文件
|
||||
downloadPath := filepath.Join(f.tempDir, fmt.Sprintf("video_%d.mp4", time.Now().Unix()))
|
||||
localVideoPath, err := f.downloadVideo(videoURL, downloadPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to download video: %w", err)
|
||||
}
|
||||
defer os.Remove(localVideoPath)
|
||||
|
||||
// 确保输出目录存在
|
||||
outputDir := filepath.Dir(outputPath)
|
||||
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||
return "", fmt.Errorf("failed to create output directory: %w", err)
|
||||
}
|
||||
|
||||
var cmd *exec.Cmd
|
||||
|
||||
if position == "last" {
|
||||
// 提取尾帧:先获取视频时长,然后提取最后一帧
|
||||
duration, err := f.GetVideoDuration(localVideoPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get video duration: %w", err)
|
||||
}
|
||||
|
||||
// 提取最后一帧(时长减去0.1秒的位置)
|
||||
seekTime := duration - 0.1
|
||||
if seekTime < 0 {
|
||||
seekTime = 0
|
||||
}
|
||||
|
||||
cmd = exec.Command("ffmpeg",
|
||||
"-ss", fmt.Sprintf("%.2f", seekTime),
|
||||
"-i", localVideoPath,
|
||||
"-vframes", "1",
|
||||
"-q:v", "2",
|
||||
"-y",
|
||||
outputPath,
|
||||
)
|
||||
} else {
|
||||
// 默认提取首帧
|
||||
cmd = exec.Command("ffmpeg",
|
||||
"-i", localVideoPath,
|
||||
"-vframes", "1",
|
||||
"-q:v", "2",
|
||||
"-y",
|
||||
outputPath,
|
||||
)
|
||||
}
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
f.log.Errorw("FFmpeg frame extraction failed", "error", err, "output", string(output))
|
||||
return "", fmt.Errorf("ffmpeg frame extraction failed: %w, output: %s", err, string(output))
|
||||
}
|
||||
|
||||
// 检查输出文件是否存在
|
||||
if _, err := os.Stat(outputPath); os.IsNotExist(err) {
|
||||
return "", fmt.Errorf("frame extraction failed: output file not created")
|
||||
}
|
||||
|
||||
f.log.Infow("Frame extracted successfully", "output", outputPath, "position", position)
|
||||
return outputPath, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user