package srv_videoinfo import ( "context" "fmt" "strings" "videoweb/pub/common/laosiji" "videoweb/pub/common/log" "videoweb/pub/common/srvdef" "videoweb/pub/common/utils" "videoweb/pub/models/videoinformationmod" "videoweb/web/webg" "go.mongodb.org/mongo-driver/bson" ) // TranscodeVideo 手动提交主视频 H265 转码。 func TranscodeVideo(ctx context.Context, videoId int64) *srvdef.SrvErr { info, serr := videoinformationmod.FindOneVideoInformation(ctx, bson.M{ videoinformationmod.FN.VideoInformation.Id: videoId, }) if serr != nil { return serr } src := strings.TrimSpace(info.Video.Url) if src == "" { return srvdef.New(srvdef.Err, "", "该视频没有可转码的源地址") } if laosiji.LaosijiClient == nil || laosiji.LaosijiDomains == nil { return srvdef.New(srvdef.Err, "", "转码服务未就绪") } if info.HevcStatus == videoinformationmod.HevcStatusPending { return srvdef.New(srvdef.Err, "", "转码请求已提交,正在转码中,请勿重复提交") } if err := SubmitTranscodeVideo(ctx, videoId, src, info.Video.FileId); err != nil { return srvdef.New(srvdef.Err, "", "提交转码失败:"+err.Error()) } return nil } func buildTranscodeSourceURL(videoUrl string) string { name := strings.TrimSpace(videoUrl) if name == "" { return "" } if !strings.Contains(name, ".m3u8") { name += ".m3u8" } host := strings.TrimSpace(webg.Conf.WebM3u8Host) if host == "" { return "" } return utils.JoinUrlPath(host, "/api/web/m3u8/"+name) } // SubmitTranscodeVideo 提交主视频转码任务。 func SubmitTranscodeVideo(ctx context.Context, videoId int64, src, fileId string) error { fileURL := buildTranscodeSourceURL(src) if fileURL == "" { return fmt.Errorf("empty transcode source url, videoUrl:%s host:%s", src, webg.Conf.WebM3u8Host) } sd, err := laosiji.LaosijiDomains.Get(ctx) if err != nil { return err } result, err := laosiji.LaosijiClient.SubmitTranscoding(ctx, fileURL, fileId, *sd, videoId) if err != nil { return err } return applyTranscodeResult(ctx, videoId, result) } // RefreshTranscodeVideo 查询转码任务状态并回写。 func RefreshTranscodeVideo(ctx context.Context, videoId int64, src, fileId string) error { fileURL := buildTranscodeSourceURL(src) if fileURL == "" { return fmt.Errorf("empty transcode source url, videoUrl:%s host:%s", src, webg.Conf.WebM3u8Host) } sd, err := laosiji.LaosijiDomains.Get(ctx) if err != nil { return err } result, found, err := laosiji.LaosijiClient.QueryTranscoding(ctx, fileURL, fileId, *sd) if err != nil { return err } if !found { return nil } return applyTranscodeResult(ctx, videoId, result) } func applyTranscodeResult(ctx context.Context, videoId int64, result laosiji.TranscodeResult) error { log.Infof("==applyTranscodeResult===> result", log.Any("videoId", videoId), log.Any("result", result)) var update bson.M switch { case result.Done: meta := toVideoMetaInfo(result.HevcMeta) if meta == nil { meta = &videoinformationmod.VideoMetaInfo{} } h265Url := normalizeH265UrlForSave(result.HevcURL) meta.M3u8URL = h265Url set := bson.M{ videoinformationmod.FN.VideoInformation.HevcStatus: videoinformationmod.HevcStatusSuccess, videoinformationmod.FN.VideoInformation.HevcMetaInfo: meta, videoinformationmod.FN.VideoInformation.Video.H265Url: h265Url, } if result.PreviewVtt != "" { set[videoinformationmod.FN.VideoInformation.PreviewVtt] = result.PreviewVtt } if result.AudioFile != "" { set[videoinformationmod.FN.VideoInformation.AudioFile] = result.AudioFile } if result.SmartCover != "" { set[videoinformationmod.FN.VideoInformation.SmartCover] = result.SmartCover } update = bson.M{"$set": set} case result.Failed: update = bson.M{ "$set": bson.M{videoinformationmod.FN.VideoInformation.HevcStatus: videoinformationmod.HevcStatusFailed}, "$inc": bson.M{videoinformationmod.FN.VideoInformation.HevcFailCount: 1}, } default: update = bson.M{"$set": bson.M{videoinformationmod.FN.VideoInformation.HevcStatus: videoinformationmod.HevcStatusPending}} } if serr := videoinformationmod.UpdateOneVideoInformation(ctx, bson.M{ videoinformationmod.FN.VideoInformation.Id: videoId, }, update); serr != nil { return fmt.Errorf("update video transcode status: %v", serr) } return nil } func normalizeH265UrlForSave(url string) string { url = strings.TrimSpace(url) return strings.TrimPrefix(url, "/") } func toVideoMetaInfo(m *laosiji.MetaInfo) *videoinformationmod.VideoMetaInfo { if m == nil { return nil } return &videoinformationmod.VideoMetaInfo{ Codec: m.Codec, Profile: m.Profile, Width: m.Width, Height: m.Height, Fps: m.Fps, VideoBitrate: m.VideoBitrate, PixFmt: m.PixFmt, AudioCodec: m.AudioCodec, AudioBitrate: m.AudioBitrate, AudioSampleRate: m.AudioSampleRate, AudioChannels: m.AudioChannels, Bitrate: m.Bitrate, Size: m.Size, Duration: m.Duration, } }