视频保存
This commit is contained in:
@@ -47,6 +47,7 @@ type MeetingRecordingService struct {
|
||||
|
||||
minioClient *minio.Client
|
||||
minioCfg *config.MinioConfig
|
||||
meetingCfg *config.MeetingConfig
|
||||
}
|
||||
|
||||
// NewMeetingRecordingService Wire Provider
|
||||
@@ -59,6 +60,7 @@ func NewMeetingRecordingService(
|
||||
mediaOrchestrator MediaOrchestrator,
|
||||
minioClient *minio.Client,
|
||||
minioCfg *config.MinioConfig,
|
||||
meetingCfg *config.MeetingConfig,
|
||||
) *MeetingRecordingService {
|
||||
return &MeetingRecordingService{
|
||||
roomDAO: roomDAO,
|
||||
@@ -69,6 +71,7 @@ func NewMeetingRecordingService(
|
||||
mediaOrchestrator: mediaOrchestrator,
|
||||
minioClient: minioClient,
|
||||
minioCfg: minioCfg,
|
||||
meetingCfg: meetingCfg,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,6 +513,11 @@ func (s *MeetingRecordingService) prepareUploadArtifact(ctx context.Context, web
|
||||
if webmPath == "" {
|
||||
return webmPath, ".webm", "video/webm", ""
|
||||
}
|
||||
if s.meetingCfg == nil || !s.meetingCfg.RecordingTranscodeEnabled {
|
||||
logs.Info(ctx, funcName, "录制转码未启用,直接上传 webm",
|
||||
zap.Int64("recording_id", recordingID), zap.String("webm_path", webmPath))
|
||||
return webmPath, ".webm", "video/webm", ""
|
||||
}
|
||||
|
||||
mp4Path, err := s.transcodeWebmToMp4(ctx, webmPath)
|
||||
if err != nil {
|
||||
@@ -535,16 +543,26 @@ func (s *MeetingRecordingService) prepareUploadArtifact(ctx context.Context, web
|
||||
// - -movflags +faststart:moov 前置,HTTP Range 即点即播
|
||||
// - -y:覆盖目标文件,避免重复 stop 时 EEXIST
|
||||
func (s *MeetingRecordingService) transcodeWebmToMp4(ctx context.Context, webmPath string) (string, error) {
|
||||
if _, err := exec.LookPath("ffmpeg"); err != nil {
|
||||
ffmpegPath := "ffmpeg"
|
||||
timeoutSec := 600
|
||||
if s.meetingCfg != nil {
|
||||
if strings.TrimSpace(s.meetingCfg.RecordingTranscodeFFmpegPath) != "" {
|
||||
ffmpegPath = strings.TrimSpace(s.meetingCfg.RecordingTranscodeFFmpegPath)
|
||||
}
|
||||
if s.meetingCfg.RecordingTranscodeTimeoutSecond > 0 {
|
||||
timeoutSec = s.meetingCfg.RecordingTranscodeTimeoutSecond
|
||||
}
|
||||
}
|
||||
if _, err := exec.LookPath(ffmpegPath); err != nil {
|
||||
return "", fmt.Errorf("ffmpeg 未安装或不在 PATH: %w", err)
|
||||
}
|
||||
mp4Path := strings.TrimSuffix(webmPath, filepath.Ext(webmPath)) + ".mp4"
|
||||
|
||||
// 转码上限:单文件最长容忍 10 分钟 CPU 时间,超时则视为失败回退
|
||||
tctx, cancel := context.WithTimeout(ctx, 10*time.Minute)
|
||||
tctx, cancel := context.WithTimeout(ctx, time.Duration(timeoutSec)*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(tctx, "ffmpeg",
|
||||
cmd := exec.CommandContext(tctx, ffmpegPath,
|
||||
"-y",
|
||||
"-i", webmPath,
|
||||
"-c:v", "libx264", "-preset", "veryfast", "-crf", "23",
|
||||
|
||||
Reference in New Issue
Block a user