12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082 |
- package sub_timeline_fixer
- //
- //import (
- // "errors"
- // "fmt"
- // "github.com/ChineseSubFinder/ChineseSubFinder/pkg/log_helper"
- // "github.com/ChineseSubFinder/ChineseSubFinder/pkg/my_util"
- // "github.com/ChineseSubFinder/ChineseSubFinder/pkg/sub_helper"
- // "github.com/ChineseSubFinder/ChineseSubFinder/pkg/vad"
- // "github.com/ChineseSubFinder/ChineseSubFinder/internal/types/sub_timeline_fiexer"
- // "github.com/ChineseSubFinder/ChineseSubFinder/internal/types/subparser"
- // "github.com/emirpasic/gods/maps/treemap"
- // "github.com/emirpasic/gods/utils"
- // "github.com/go-echarts/go-echarts/v2/opts"
- // "github.com/grd/stat"
- // "github.com/james-bowman/nlp/measures/pairwise"
- // "github.com/mndrix/tukey"
- // "github.com/panjf2000/ants/v2"
- // "golang.org/x/net/context"
- // "gonum.org/v1/gonum/mat"
- // "math"
- // "os"
- // "sort"
- // "strings"
- // "sync"
- // "time"
- //)
- //
- //type SubTimelineFixer struct {
- // log *logrus.Logger
- // FixerConfig sub_timeline_fiexer.SubTimelineFixerConfig
- //}
- //
- //func NewSubTimelineFixer(log *logrus.Logger, fixerConfig sub_timeline_fiexer.SubTimelineFixerConfig) *SubTimelineFixer {
- // return &SubTimelineFixer{
- // log: log,
- // FixerConfig: fixerConfig,
- // }
- //}
- //
- //// StopWordCounter 停止词统计
- //func (s *SubTimelineFixer) StopWordCounter(inString string, per int) []string {
- // statisticTimes := make(map[string]int)
- // wordsLength := strings.Fields(inString)
- //
- // for counts, word := range wordsLength {
- // // 判断key是否存在,这个word是字符串,这个counts是统计的word的次数。
- // word, ok := statisticTimes[word]
- // if ok {
- // word = word
- // statisticTimes[wordsLength[counts]] = statisticTimes[wordsLength[counts]] + 1
- // } else {
- // statisticTimes[wordsLength[counts]] = 1
- // }
- // }
- //
- // stopWords := make([]string, 0)
- // mapByValue := sortMapByValue(statisticTimes)
- //
- // breakIndex := len(mapByValue) * per / 100
- // for index, wordInfo := range mapByValue {
- // if index > breakIndex {
- // break
- // }
- // stopWords = append(stopWords, wordInfo.Name)
- // }
- //
- // return stopWords
- //}
- //
- //// FixSubTimelineOneOffsetTime 校正整个字幕文件的时间轴,适用于一个偏移值的情况
- //func (s *SubTimelineFixer) FixSubTimelineOneOffsetTime(infoSrc *subparser.FileInfo, inOffsetTime float64, desSaveSubFileFullPath string) (string, error) {
- //
- // /*
- // 从解析的实例中,正常来说是可以匹配出所有的 Dialogue 对话的 Start 和 End time 的信息
- // 然后找到对应的字幕的文件,进行文件内容的替换来做时间轴的校正
- // */
- // // 偏移时间
- // offsetTime := time.Duration(inOffsetTime*1000) * time.Millisecond
- // fixContent := infoSrc.Content
- // /*
- // 这里进行时间转字符串的时候有一点比较特殊
- // 正常来说输出的格式是类似 15:04:05.00
- // 那么有个问题,字幕的时间格式是 0:00:12.00, 小时,是个数,除非有跨度到 20 小时的视频,不然小时就应该是个数
- // 这就需要一个额外的函数去处理这些情况
- // */
- // timeFormat := infoSrc.GetTimeFormat()
- // for _, srcOneDialogue := range infoSrc.Dialogues {
- //
- // timeStart, err := my_util.ParseTime(srcOneDialogue.StartTime)
- // if err != nil {
- // return "", err
- // }
- // timeEnd, err := my_util.ParseTime(srcOneDialogue.EndTime)
- // if err != nil {
- // return "", err
- // }
- //
- // fixTimeStart := timeStart.Add(offsetTime)
- // fixTimeEnd := timeEnd.Add(offsetTime)
- //
- // fixContent = strings.ReplaceAll(fixContent, srcOneDialogue.StartTime, my_util.Time2SubTimeString(fixTimeStart, timeFormat))
- // fixContent = strings.ReplaceAll(fixContent, srcOneDialogue.EndTime, my_util.Time2SubTimeString(fixTimeEnd, timeFormat))
- // }
- //
- // dstFile, err := os.Create(desSaveSubFileFullPath)
- // if err != nil {
- // return "", err
- // }
- // defer func() {
- // _ = dstFile.Close()
- // }()
- // _, err = dstFile.WriteString(fixContent)
- // if err != nil {
- // return "", err
- // }
- // return fixContent, nil
- //}
- //
- //// FixSubTimelineByFixResults V2 专用的时间校正函数
- //func (s SubTimelineFixer) FixSubTimelineByFixResults(infoSrc *subparser.FileInfo, srcUnitNew *sub_helper.SubUnit, fixedResults []FixResult, desSaveSubFileFullPath string) (string, error) {
- //
- // startTime := srcUnitNew.GetStartTime(true)
- // startTimeBaseDouble := my_util.Time2SecondNumber(startTime)
- // /*
- // 这里拿到的 fixedResults ,是进行过 V2_FrontAndEndPerSrc 头尾去除
- // 那么调整目标字幕的时候,需要考虑截取掉的部分也要算进去
- // */
- // /*
- // 从解析的实例中,正常来说是可以匹配出所有的 Dialogue 对话的 Start 和 End time 的信息
- // 然后找到对应的字幕的文件,进行文件内容的替换来做时间轴的校正
- // */
- // fixContent := infoSrc.Content
- // /*
- // 这里进行时间转字符串的时候有一点比较特殊
- // 正常来说输出的格式是类似 15:04:05.00
- // 那么有个问题,字幕的时间格式是 0:00:12.00, 小时,是个数,除非有跨度到 20 小时的视频,不然小时就应该是个数
- // 这就需要一个额外的函数去处理这些情况
- // */
- // timeFormat := infoSrc.GetTimeFormat()
- // cacheIndex := 0
- // /*
- // 这里的理想情况是 Dialogues,每一句话都是递增的对白时间
- // 但是实际情况可能是,前面几个对白是特效、音乐的备注,那么他们的跨度可以很大
- // 然后才到正常的对话对白,这样就出现不是递增的时间对白情况
- // 那么就需要对 Dialogues 进行排序,然后再进行处理
- // */
- // sort.Sort(subparser.OneDialogueByStartTime(infoSrc.Dialogues))
- //
- // for index, srcOneDialogue := range infoSrc.Dialogues {
- //
- // timeStart, err := my_util.ParseTime(srcOneDialogue.StartTime)
- // if err != nil {
- // return "", err
- // }
- // timeEnd, err := my_util.ParseTime(srcOneDialogue.EndTime)
- // if err != nil {
- // return "", err
- // }
- //
- // inOffsetTime := 0.0
- // orgStartTimeDouble := my_util.Time2SecondNumber(timeStart)
- // for cacheIndex < len(fixedResults) {
- //
- // inRange, nowOffsetTime := fixedResults[cacheIndex].InRange(startTimeBaseDouble, orgStartTimeDouble)
- // if inRange == false {
- // // 大于当前的范围,递增一个区间进行再次的判断
- // // 但是需要确定的是,递增出来的这个区间的 Index 是有效的,如果是无效的,那么就使用最后一个区间的偏移时间
- // cacheIndex++
- // continue
- // } else {
- // inOffsetTime = nowOffsetTime
- // break
- // }
- // }
- // if cacheIndex >= len(fixedResults) {
- // // 下一个区间的 Index 已经越界了,那么就使用最后一个区间的偏移
- // inOffsetTime = fixedResults[len(fixedResults)-1].NewMean
- // }
- // // 偏移时间
- // println(index, inOffsetTime)
- // offsetTime := time.Duration(inOffsetTime*1000) * time.Millisecond
- // fixTimeStart := timeStart.Add(offsetTime)
- // fixTimeEnd := timeEnd.Add(offsetTime)
- //
- // fixContent = strings.ReplaceAll(fixContent, srcOneDialogue.StartTime, "Index:"+fmt.Sprintf("%d-", index)+my_util.Time2SubTimeString(fixTimeStart, timeFormat))
- // fixContent = strings.ReplaceAll(fixContent, srcOneDialogue.EndTime, my_util.Time2SubTimeString(fixTimeEnd, timeFormat))
- // }
- //
- // dstFile, err := os.Create(desSaveSubFileFullPath)
- // if err != nil {
- // return "", err
- // }
- // defer func() {
- // _ = dstFile.Close()
- // }()
- // _, err = dstFile.WriteString(fixContent)
- // if err != nil {
- // return "", err
- // }
- // return fixContent, nil
- //}
- //
- ///*
- // 对于 V1 版本的字幕时间轴校正来说,是有特殊的前置要求的
- // 1. 视频要有英文字幕
- // 2. 外置的字幕必须是中文的双语字幕(简英、繁英)
- //*/
- //// GetOffsetTimeV1 暂时只支持英文的基准字幕,源字幕必须是双语中英字幕
- //func (s *SubTimelineFixer) GetOffsetTimeV1(infoBase, infoSrc *subparser.FileInfo, staticLineFileSavePath string, debugInfoFileSavePath string) (bool, float64, float64, error) {
- //
- // var debugInfos = make([]string, 0)
- // // 构建基准语料库,目前阶段只需要考虑是 En 的就行了
- // var baseCorpus = make([]string, 0)
- // var baseDialogueFilterMap = make(map[int]int, 0)
- // /*
- // 这里原来的写法是所有的 base 的都放进去匹配,这样会带来一些不必要的对白
- // 需要剔除空白。那么就需要建立一个转换的字典
- // */
- // for index, oneDialogueEx := range infoBase.DialoguesFilterEx {
- // if oneDialogueEx.EnLine == "" {
- // continue
- // }
- // baseCorpus = append(baseCorpus, oneDialogueEx.EnLine)
- // baseDialogueFilterMap[len(baseCorpus)-1] = index
- // }
- // // 初始化
- // pipLine, tfidf, err := NewTFIDF(baseCorpus)
- // if err != nil {
- // return false, 0, 0, err
- // }
- //
- // /*
- // 确认两个字幕间的偏移,暂定的方案是两边都连续匹配上 5 个索引,再抽取一个对话的时间进行修正计算
- // */
- // maxCompareDialogue := s.FixerConfig.V1_MaxCompareDialogue
- // // 基线的长度
- // _, docsLength := tfidf.Dims()
- // var matchIndexList = make([]MatchIndex, 0)
- // sc := NewSubCompare(maxCompareDialogue)
- // // 开始比较相似度,默认认为是 Ch_en 就行了
- // for srcIndex := 0; srcIndex < len(infoSrc.DialoguesFilterEx); {
- //
- // srcOneDialogueEx := infoSrc.DialoguesFilterEx[srcIndex]
- // // 这里只考虑 英文 的语言
- // if srcOneDialogueEx.EnLine == "" {
- // srcIndex++
- // continue
- // }
- // // run the query through the same pipeline that was fitted to the corpus and
- // // to project it into the same dimensional space
- // queryVector, err := pipLine.Transform(srcOneDialogueEx.EnLine)
- // if err != nil {
- // return false, 0, 0, err
- // }
- // // iterate over document feature vectors (columns) in the LSI matrix and compare
- // // with the query vector for similarity. Similarity is determined by the difference
- // // between the angles of the vectors known as the cosine similarity
- // highestSimilarity := -1.0
- // // 匹配上的基准的索引
- // var baseIndex int
- // // 这里理论上需要把所有的基线遍历一次,但是,一般来说,两个字幕不可能差距在 50 行
- // // 这样的好处是有助于提高搜索的性能
- // // 那么就以当前的 src 的位置,向前、向后各 50 来遍历
- // nowMaxScanLength := srcIndex + 50
- // nowMinScanLength := srcIndex - 50
- // if nowMinScanLength < 0 {
- // nowMinScanLength = 0
- // }
- // if nowMaxScanLength > docsLength {
- // nowMaxScanLength = docsLength
- // }
- // for i := nowMinScanLength; i < nowMaxScanLength; i++ {
- // similarity := pairwise.CosineSimilarity(queryVector.(mat.ColViewer).ColView(0), tfidf.(mat.ColViewer).ColView(i))
- // if similarity > highestSimilarity {
- // baseIndex = i
- // highestSimilarity = similarity
- // }
- // }
- //
- // startBaseIndex, startSrcIndex := sc.GetStartIndex()
- // if sc.Add(baseIndex, srcIndex) == false {
- // sc.Clear()
- // srcIndex = startSrcIndex + 1
- // continue
- // //sc.Add(baseIndex, srcIndex)
- // }
- // if sc.Check() == false {
- // srcIndex++
- // continue
- // } else {
- // sc.Clear()
- // }
- //
- // matchIndexList = append(matchIndexList, MatchIndex{
- // BaseNowIndex: startBaseIndex,
- // //BaseNowIndex: baseDialogueFilterMap[startBaseIndex],
- // SrcNowIndex: startSrcIndex,
- // Similarity: highestSimilarity,
- // })
- //
- // //println(fmt.Sprintf("Similarity: %f Base[%d] %s-%s '%s' <--> Src[%d] %s-%s '%s'",
- // // highestSimilarity,
- // // baseIndex, infoBase.DialoguesFilterEx[baseIndex].relativelyStartTime, infoBase.DialoguesFilterEx[baseIndex].relativelyEndTime, baseCorpus[baseIndex],
- // // srcIndex, srcOneDialogueEx.relativelyStartTime, srcOneDialogueEx.relativelyEndTime, srcOneDialogueEx.EnLine))
- //
- // srcIndex++
- // }
- //
- // var startDiffTimeLineData = make([]opts.LineData, 0)
- // var endDiffTimeLineData = make([]opts.LineData, 0)
- // var tmpStartDiffTime = make([]float64, 0)
- // var tmpEndDiffTime = make([]float64, 0)
- // var startDiffTimeList = make(stat.Float64Slice, 0)
- // var endDiffTimeList = make(stat.Float64Slice, 0)
- // var xAxis = make([]string, 0)
- // // 上面找出了连续匹配 maxCompareDialogue:N 次的字幕语句块
- // // 求出平均时间偏移
- // for mIndex, matchIndexItem := range matchIndexList {
- //
- // for i := 0; i < maxCompareDialogue; i++ {
- // // 这里会统计连续的这 5 句话的时间差
- // //tmpBaseIndex := matchIndexItem.BaseNowIndex + i
- // tmpBaseIndex := baseDialogueFilterMap[matchIndexItem.BaseNowIndex+i]
- // tmpSrcIndex := matchIndexItem.SrcNowIndex + i
- //
- // baseTimeStart, err := my_util.ParseTime(infoBase.DialoguesFilterEx[tmpBaseIndex].StartTime)
- // if err != nil {
- // return false, 0, 0, err
- // }
- // baseTimeEnd, err := my_util.ParseTime(infoBase.DialoguesFilterEx[tmpBaseIndex].EndTime)
- // if err != nil {
- // return false, 0, 0, err
- // }
- // srtTimeStart, err := my_util.ParseTime(infoSrc.DialoguesFilterEx[tmpSrcIndex].StartTime)
- // if err != nil {
- // return false, 0, 0, err
- // }
- // srtTimeEnd, err := my_util.ParseTime(infoSrc.DialoguesFilterEx[tmpSrcIndex].EndTime)
- // if err != nil {
- // return false, 0, 0, err
- // }
- //
- // TimeDiffStart := baseTimeStart.Sub(srtTimeStart)
- // TimeDiffEnd := baseTimeEnd.Sub(srtTimeEnd)
- //
- // startDiffTimeLineData = append(startDiffTimeLineData, opts.LineData{Value: TimeDiffStart.Seconds()})
- // endDiffTimeLineData = append(endDiffTimeLineData, opts.LineData{Value: TimeDiffEnd.Seconds()})
- //
- // tmpStartDiffTime = append(tmpStartDiffTime, TimeDiffStart.Seconds())
- // tmpEndDiffTime = append(tmpEndDiffTime, TimeDiffEnd.Seconds())
- //
- // startDiffTimeList = append(startDiffTimeList, TimeDiffStart.Seconds())
- // endDiffTimeList = append(endDiffTimeList, TimeDiffEnd.Seconds())
- //
- // xAxis = append(xAxis, fmt.Sprintf("%d_%d", mIndex, i))
- //
- // debugInfos = append(debugInfos, "bs "+infoBase.DialoguesFilterEx[tmpBaseIndex].StartTime+" <-> "+infoBase.DialoguesFilterEx[tmpBaseIndex].EndTime)
- // debugInfos = append(debugInfos, "sc "+infoSrc.DialoguesFilterEx[tmpSrcIndex].StartTime+" <-> "+infoSrc.DialoguesFilterEx[tmpSrcIndex].EndTime)
- // debugInfos = append(debugInfos, "StartDiffTime: "+fmt.Sprintf("%f", TimeDiffStart.Seconds()))
- // //println(fmt.Sprintf("Diff Start-End: %s - %s Base[%d] %s-%s '%s' <--> Src[%d] %s-%s '%s'",
- // // TimeDiffStart, TimeDiffEnd,
- // // tmpBaseIndex, infoBase.DialoguesFilterEx[tmpBaseIndex].relativelyStartTime, infoBase.DialoguesFilterEx[tmpBaseIndex].relativelyEndTime, infoBase.DialoguesFilterEx[tmpBaseIndex].EnLine,
- // // tmpSrcIndex, infoSrc.DialoguesFilterEx[tmpSrcIndex].relativelyStartTime, infoSrc.DialoguesFilterEx[tmpSrcIndex].relativelyEndTime, infoSrc.DialoguesFilterEx[tmpSrcIndex].EnLine))
- // }
- // debugInfos = append(debugInfos, "---------------------------------------------")
- // //println("---------------------------------------------")
- // }
- //
- // oldMean := stat.Mean(startDiffTimeList)
- // oldSd := stat.Sd(startDiffTimeList)
- // newMean := -1.0
- // newSd := -1.0
- // per := 1.0
- //
- // // 如果 SD 较大的时候才需要剔除
- // if oldSd > 0.1 {
- // var outliersMap = make(map[float64]int, 0)
- // outliers, _, _ := tukey.Outliers(0.3, tmpStartDiffTime)
- // for _, outlier := range outliers {
- // outliersMap[outlier] = 0
- // }
- // var newStartDiffTimeList = make([]float64, 0)
- // for _, f := range tmpStartDiffTime {
- //
- // _, ok := outliersMap[f]
- // if ok == true {
- // continue
- // }
- //
- // newStartDiffTimeList = append(newStartDiffTimeList, f)
- // }
- //
- // orgLen := startDiffTimeList.Len()
- // startDiffTimeList = make(stat.Float64Slice, 0)
- // for _, f := range newStartDiffTimeList {
- // startDiffTimeList = append(startDiffTimeList, f)
- // }
- // newLen := startDiffTimeList.Len()
- //
- // per = float64(newLen) / float64(orgLen)
- //
- // newMean = stat.Mean(startDiffTimeList)
- // newSd = stat.Sd(startDiffTimeList)
- // }
- //
- // if newMean == -1.0 {
- // newMean = oldMean
- // }
- // if newSd == -1.0 {
- // newSd = oldSd
- // }
- //
- // // 不为空的时候,生成调试文件
- // if staticLineFileSavePath != "" {
- // //staticLineFileSavePath = "bar.html"
- // err = SaveStaticLineV1(staticLineFileSavePath, infoBase.Name, infoSrc.Name,
- // per, oldMean, oldSd, newMean, newSd, xAxis,
- // startDiffTimeLineData, endDiffTimeLineData)
- // if err != nil {
- // return false, 0, 0, err
- // }
- // }
- //
- // // 跳过的逻辑是 mean 是 0 ,那么现在如果判断有问题,缓存的调试文件继续生成,然后强制返回 0 来跳过后续的逻辑
- // // 这里需要考虑,找到的连续 5 句话匹配的有多少句,占比整体所有的 Dialogue 是多少,太低也需要跳过
- // matchIndexLineCount := len(matchIndexList) * maxCompareDialogue
- // //perMatch := float64(matchIndexLineCount) / float64(len(infoSrc.DialoguesFilterEx))
- // perMatch := float64(matchIndexLineCount) / float64(len(baseCorpus))
- // if perMatch < s.FixerConfig.V1_MinMatchedPercent {
- // tmpContent := infoSrc.Name + fmt.Sprintf(" Sequence match %d dialogues (< %f%%), Skip,", s.FixerConfig.V1_MaxCompareDialogue, s.FixerConfig.V1_MinMatchedPercent*100) + fmt.Sprintf(" %f%% ", perMatch*100)
- //
- // debugInfos = append(debugInfos, tmpContent)
- //
- // s.log.Infoln(tmpContent)
- // } else {
- // tmpContent := infoSrc.Name + fmt.Sprintf(" Sequence match %d dialogues,", s.FixerConfig.V1_MaxCompareDialogue) + fmt.Sprintf(" %f%% ", perMatch*100)
- //
- // debugInfos = append(debugInfos, tmpContent)
- //
- // s.log.Infoln(tmpContent)
- // }
- //
- // // 输出调试的匹配时间轴信息的列表
- // if debugInfoFileSavePath != "" {
- // err = my_util.WriteStrings2File(debugInfoFileSavePath, debugInfos)
- // if err != nil {
- // return false, 0, 0, err
- // }
- // }
- // // 虽然有条件判断是认为有问题的,但是返回值还是要填写除去的
- // if perMatch < s.FixerConfig.V1_MinMatchedPercent {
- // return false, newMean, newSd, nil
- // }
- //
- // return true, newMean, newSd, nil
- //}
- //
- //// GetOffsetTimeV2 使用内置的字幕校正外置的字幕时间轴
- //func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit, audioVadList []vad.VADInfo) (bool, []FixResult, error) {
- //
- // // -------------------------------------------------
- // /*
- // 开始针对对白单元进行匹配
- // 下面的逻辑需要参考 FFT识别流程.jpg 这个图示来理解
- // 实际实现的时候,会在上述 srcUnit 上,做一个滑动窗口来做匹配,80% 是窗口,20% 用于移动
- // 步长固定在 10 步
- // */
- // audioFloatList := vad.GetFloatSlice(audioVadList)
- //
- // srcVADLen := len(srcUnit.VADList)
- // // 滑动窗口的长度
- // srcWindowLen := int(float64(srcVADLen) * s.FixerConfig.V2_WindowMatchPer)
- // // 划分为 4 个区域,每一个部分的长度
- // const parts = 10
- // perPartLen := srcVADLen / parts
- // matchedInfos := make([]MatchInfo, 0)
- //
- // subVADBlockInfos := make([]SubVADBlockInfo, 0)
- // for i := 0; i < parts; i++ {
- //
- // // 滑动窗体的起始 Index
- // srcSlideStartIndex := i * perPartLen
- // // 滑动的距离
- // srcSlideLen := perPartLen
- // // 一步的长度
- // oneStep := perPartLen / s.FixerConfig.V2_CompareParts
- // if srcSlideLen <= 0 {
- // srcSlideLen = 1
- // }
- // if oneStep <= 0 {
- // oneStep = 1
- // }
- // // -------------------------------------------------
- // windowInfo := WindowInfo{
- // BaseAudioFloatList: audioFloatList,
- // BaseUnit: baseUnit,
- // SrcUnit: srcUnit,
- // MatchedTimes: 0,
- // SrcWindowLen: srcWindowLen,
- // SrcSlideStartIndex: srcSlideStartIndex,
- // SrcSlideLen: srcSlideLen,
- // OneStep: oneStep,
- // }
- // subVADBlockInfos = append(subVADBlockInfos, SubVADBlockInfo{
- // Index: i,
- // StartIndex: srcSlideStartIndex,
- // EndIndex: srcSlideStartIndex + srcSlideLen,
- // })
- // // 实际 FFT 的匹配逻辑函数
- // // 时间轴差值数组
- // matchInfo, err := s.slidingWindowProcessorV2(&windowInfo)
- // if err != nil {
- // return false, nil, err
- // }
- //
- // matchedInfos = append(matchedInfos, *matchInfo)
- // }
- //
- // fixedResults := make([]FixResult, 0)
- // sdLessCount := 0
- // // 这里的是 matchedInfos 是顺序的
- // for index, matchInfo := range matchedInfos {
- //
- // s.log.Infoln(index, "------------------------------------")
- // outCorrelationFixResult := s.calcMeanAndSDV2(matchInfo.StartDiffTimeListEx, matchInfo.StartDiffTimeList)
- // s.log.Infoln(fmt.Sprintf("FFTAligner Old Mean: %v SD: %f Per: %v", outCorrelationFixResult.OldMean, outCorrelationFixResult.OldSD, outCorrelationFixResult.Per))
- // s.log.Infoln(fmt.Sprintf("FFTAligner New Mean: %v SD: %f Per: %v", outCorrelationFixResult.NewMean, outCorrelationFixResult.NewSD, outCorrelationFixResult.Per))
- //
- // value, indexMax := matchInfo.StartDiffTimeMap.Max()
- // s.log.Infoln("FFTAligner Max score:", fmt.Sprintf("%v", value.(float64)), "Time:", fmt.Sprintf("%v", matchInfo.StartDiffTimeList[indexMax.(int)]))
- //
- // outCorrelationFixResult.StartVADIndex = index * perPartLen
- // outCorrelationFixResult.EndVADIndex = index*perPartLen + perPartLen
- // fixedResults = append(fixedResults, outCorrelationFixResult)
- //
- // if outCorrelationFixResult.NewSD < 0.1 {
- // sdLessCount++
- // }
- // }
- //
- // // 如果 0.1 sd 以下的占比低于 70% 那么就认为字幕匹配失败
- // perLess := float64(sdLessCount) / float64(len(matchedInfos))
- // if perLess < 0.7 {
- // return false, nil, nil
- // }
- //
- // // matchedInfos 与 fixedResults 是对等的关系,fixedResults 中是计算过 Mean 的值,而 matchedInfos 有原始的值
- // for i, info := range matchedInfos {
- // for j := 0; j < len(info.IndexMatchWindowInfoMap); j++ {
- //
- // value, bFound := info.IndexMatchWindowInfoMap[j]
- // if bFound == false {
- // continue
- // }
- //
- // fixedResults[i].MatchWindowInfos = append(fixedResults[i].MatchWindowInfos, value)
- // }
- // }
- // /*
- // 如果 outCorrelationFixResult 的 SD > 0.1,那么大概率这个时间轴的值匹配的有问题,需要向左或者向右找一个值进行继承
- // -4 0.001
- // -4 0.001
- // -4 0.001
- // -200 0.1
- // -4 0.001
- // 比如这种情况,那么就需要向左找到 -4 去继承。
- // 具体的实现:
- // 找到一个 SD > 0.1 的项目,那么就需要从左边和右边同时对比
- // 首先是他们的差值要在 0.3s (绝对值)以内,优先往左边找,如果绝对值成立则判断 SD (SD 必须 < 0.1)
- // 如果只是 SD 不成立,那么就继续往左,继续判断差值和 SD。
- // 如果都找不到合适的,就要回到”起点“,从右开始找,逻辑一样
- // 直到没有找到合适的信息,就报错
- // */
- // // 进行细节的修正
- // for index, fixedResult := range fixedResults {
- // // SD 大于 0.1 或者是 当前的 NewMean 与上一个点的 NewMean 差值大于 0.3
- // if fixedResult.NewSD >= 0.1 || (index > 1 && math.Abs(fixedResult.NewMean-fixedResults[index-1].NewMean) > 0.3) {
- // bok, newMean, newSD := s.fixOnePartV2(index, fixedResults)
- // if bok == true {
- // fixedResults[index].NewMean = newMean
- // fixedResults[index].NewSD = newSD
- // }
- // }
- // }
- //
- // return true, fixedResults, nil
- //}
- //
- //// fixOnePartV2 轻微地跳动可以根据左或者右去微调
- //func (s SubTimelineFixer) fixOnePartV2(startIndex int, fixedResults []FixResult) (bool, float64, float64) {
- //
- // /*
- // 找到这样情况的进行修正
- // */
- // // 先往左
- // if startIndex-1 >= 0 {
- // // 说明至少可以往左
- // // 如果左边的这个值,与当前值超过了 0.3 的绝对差值,那么是不适合的,就需要往右找
- // if math.Abs(fixedResults[startIndex-1].NewMean-fixedResults[startIndex].NewMean) < 0.3 {
- // // 差值在接受的范围内,那么就使用这个左边的值去校正当前的值
- // return true, fixedResults[startIndex-1].NewMean, fixedResults[startIndex-1].NewSD
- // }
- // }
- //
- // // 如果上面的理想情况都没有进去,那么就是这个差值很大
- // if fixedResults[startIndex].NewSD > 1 {
- // // SD 比较大,可能当前的位置是值是错误的,那么直接就使用左边的值
- // /*
- // -6.3 0.06
- // -146.85 243.83
- // */
- // if startIndex-1 >= 0 {
- // return true, fixedResults[startIndex-1].NewMean, fixedResults[startIndex-1].NewSD
- // }
- // } else {
- // // SD 不是很大,可能就是正常的字幕分段的时间轴偏移的 越接处 !
- // // 那么需要取,越接处,前三和后三,进行均值计算
- // /*
- // -6.21
- // -6.22
- // -6.29 0.06
- //
- // -7.13 0.14 越接处
- //
- // -7.32
- // -7.31
- // -7.44
- // */
- // left3Mean := 0.0
- // right3Mean := 0.0
- // // 向左,三个或者三个位置
- // if startIndex-3 >= 0 {
- // left3Mean = float64(fixedResults[startIndex-1].NewMean+fixedResults[startIndex-2].NewMean+fixedResults[startIndex-3].NewMean) / 3.0
- // } else if startIndex-2 >= 0 {
- // left3Mean = float64(fixedResults[startIndex-1].NewMean+fixedResults[startIndex-2].NewMean) / 2.0
- // } else {
- // return false, 0, 0
- // }
- // // 向右,三个或者三个位置
- // if startIndex+3 >= 0 {
- // right3Mean = float64(fixedResults[startIndex+1].NewMean+fixedResults[startIndex+2].NewMean+fixedResults[startIndex+3].NewMean) / 3.0
- // } else if startIndex+2 >= 0 {
- // right3Mean = float64(fixedResults[startIndex+1].NewMean+fixedResults[startIndex+2].NewMean) / 2.0
- // } else {
- // return false, 0, 0
- // }
- // // 将这个匹配的段中的子分段的时间轴偏移都进行一次计算,推算出到底是怎么样的配比可以得到这样的偏移结论
- // for i, info := range fixedResults[startIndex].MatchWindowInfos {
- //
- // perPartLen := info.EndVADIndex - info.StartVADIndex
- // op := OverParts{}
- // // xLen 计算公式见推到公式截图
- // xLen := (info.TimeDiffStartCorrelation*float64(perPartLen) - right3Mean*float64(perPartLen)) / (left3Mean - right3Mean)
- // yLen := float64(perPartLen) - xLen
- //
- // op.XLen = xLen
- // op.YLen = yLen
- // op.XMean = left3Mean
- // op.YMean = right3Mean
- //
- // fixedResults[startIndex].IsOverParts = true
- // fixedResults[startIndex].MatchWindowInfos[i].OP = op
- // }
- //
- // return true, fixedResults[startIndex+1].NewMean, fixedResults[startIndex+1].NewSD
- // }
- //
- // return false, 0, 0
- //}
- //
- //// slidingWindowProcessorV2 滑动窗口计算时间轴偏移
- //func (s *SubTimelineFixer) slidingWindowProcessorV2(windowInfo *WindowInfo) (*MatchInfo, error) {
- //
- // // -------------------------------------------------
- // var bUseSubOrAudioAsBase = true
- // if windowInfo.BaseUnit == nil && windowInfo.BaseAudioFloatList != nil {
- // // 使用 音频 来进行匹配
- // bUseSubOrAudioAsBase = false
- // } else if windowInfo.BaseUnit != nil {
- // // 使用 字幕 来进行匹配
- // bUseSubOrAudioAsBase = true
- // } else {
- // return nil, errors.New("GetOffsetTimeV2 input baseUnit or AudioVad is nil")
- // }
- // // -------------------------------------------------
- // outMatchInfo := MatchInfo{
- // IndexMatchWindowInfoMap: make(map[int]MatchWindowInfo, 0),
- // StartDiffTimeList: make([]float64, 0),
- // StartDiffTimeMap: treemap.NewWith(utils.Float64Comparator),
- // StartDiffTimeListEx: make(stat.Float64Slice, 0),
- // }
- // fixFunc := func(i interface{}) error {
- // inData := i.(InputData)
- // // -------------------------------------------------
- // // 开始匹配
- // // 这里的对白单元,当前的 Base 进行对比,详细示例见图解。Step 2 中橙色的区域
- // fffAligner := NewFFTAligner(DefaultMaxOffsetSeconds, SampleRate)
- // var bok = false
- // var nowBaseStartTime = 0.0
- // var offsetIndex = 0
- // var score = 0.0
- // srcMaxLen := 0
- // // 图解,参考 Step 3
- // if bUseSubOrAudioAsBase == false {
- // // 使用 音频 来进行匹配
- // // 去掉头和尾,具体百分之多少,见 V2_FrontAndEndPerBase
- // audioCutLen := int(float64(len(inData.BaseAudioVADList)) * s.FixerConfig.V2_FrontAndEndPerBase)
- //
- // srcMaxLen = windowInfo.SrcWindowLen + inData.OffsetIndex
- // if srcMaxLen >= len(inData.SrcUnit.GetVADFloatSlice()) {
- // srcMaxLen = len(inData.SrcUnit.GetVADFloatSlice()) - 1
- // }
- // offsetIndex, score = fffAligner.Fit(inData.BaseAudioVADList[audioCutLen:len(inData.BaseAudioVADList)-audioCutLen], inData.SrcUnit.GetVADFloatSlice()[inData.OffsetIndex:srcMaxLen])
- // realOffsetIndex := offsetIndex + audioCutLen
- // if realOffsetIndex < 0 {
- // return nil
- // }
- // // offsetIndex 这里得到的是 10ms 为一个单位的 OffsetIndex
- // nowBaseStartTime = vad.GetAudioIndex2Time(realOffsetIndex)
- //
- // } else {
- // // 使用 字幕 来进行匹配
- //
- // srcMaxLen = inData.OffsetIndex + windowInfo.SrcWindowLen
- // if srcMaxLen >= len(inData.SrcUnit.GetVADFloatSlice()) {
- // srcMaxLen = len(inData.SrcUnit.GetVADFloatSlice()) - 1
- // }
- // offsetIndex, score = fffAligner.Fit(inData.BaseUnit.GetVADFloatSlice(), inData.SrcUnit.GetVADFloatSlice()[inData.OffsetIndex:srcMaxLen])
- // if offsetIndex < 0 {
- // return nil
- // }
- // bok, nowBaseStartTime = inData.BaseUnit.GetIndexTimeNumber(offsetIndex, true)
- // if bok == false {
- // return nil
- // }
- // }
- // // 需要校正的字幕
- // bok, nowSrcStartTime := inData.SrcUnit.GetIndexTimeNumber(inData.OffsetIndex, true)
- // if bok == false {
- // return nil
- // }
- // // 时间差值
- // TimeDiffStartCorrelation := nowBaseStartTime - nowSrcStartTime
- // s.log.Debugln("------------")
- // s.log.Debugln("OffsetTime:", fmt.Sprintf("%v", TimeDiffStartCorrelation),
- // "offsetIndex:", offsetIndex,
- // "score:", fmt.Sprintf("%v", score))
- //
- // mutexFixV2.Lock()
- // // 这里的未必的顺序的,所以才有 IndexMatchWindowInfoMap 的存在的意义
- // outMatchInfo.IndexMatchWindowInfoMap[inData.Index] = MatchWindowInfo{TimeDiffStartCorrelation: TimeDiffStartCorrelation,
- // StartVADIndex: inData.OffsetIndex,
- // EndVADIndex: srcMaxLen}
- // outMatchInfo.StartDiffTimeList = append(outMatchInfo.StartDiffTimeList, TimeDiffStartCorrelation)
- // outMatchInfo.StartDiffTimeListEx = append(outMatchInfo.StartDiffTimeListEx, TimeDiffStartCorrelation)
- // outMatchInfo.StartDiffTimeMap.Put(score, windowInfo.MatchedTimes)
- // windowInfo.MatchedTimes++
- // mutexFixV2.Unlock()
- // // -------------------------------------------------
- // return nil
- // }
- // // -------------------------------------------------
- // antPool, err := ants.NewPoolWithFunc(s.FixerConfig.V2_FixThreads, func(inData interface{}) {
- // data := inData.(InputData)
- // defer data.Wg.Done()
- // ctx, cancel := context.WithTimeout(context.Background(), time.Duration(s.FixerConfig.V2_SubOneUnitProcessTimeOut)*time.Second)
- // defer cancel()
- //
- // done := make(chan error, 1)
- // panicChan := make(chan interface{}, 1)
- // go func() {
- // defer func() {
- // if p := recover(); p != nil {
- // panicChan <- p
- // }
- //close(done)
- //close(panicChan)
- // }()
- //
- // done <- fixFunc(inData)
- // }()
- //
- // select {
- // case err := <-done:
- // if err != nil {
- // s.log.Errorln("GetOffsetTimeV2.NewPoolWithFunc done with Error", err.Error())
- // }
- // return
- // case p := <-panicChan:
- // s.log.Errorln("GetOffsetTimeV2.NewPoolWithFunc got panic", p)
- // return
- // case <-ctx.Done():
- // s.log.Errorln("GetOffsetTimeV2.NewPoolWithFunc got time out", ctx.Err())
- // return
- // }
- // })
- // if err != nil {
- // return nil, err
- // }
- // defer antPool.Release()
- // // -------------------------------------------------
- // wg := sync.WaitGroup{}
- // index := 0
- // for i := windowInfo.SrcSlideStartIndex; i < windowInfo.SrcSlideStartIndex+windowInfo.SrcSlideLen-1; {
- // wg.Add(1)
- //
- // if bUseSubOrAudioAsBase == true {
- // // 使用字幕
- // err = antPool.Invoke(InputData{Index: index, BaseUnit: *windowInfo.BaseUnit, SrcUnit: *windowInfo.SrcUnit, OffsetIndex: i, Wg: &wg})
- // } else {
- // // 使用音频
- // err = antPool.Invoke(InputData{Index: index, BaseAudioVADList: windowInfo.BaseAudioFloatList, SrcUnit: *windowInfo.SrcUnit, OffsetIndex: i, Wg: &wg})
- // }
- //
- // if err != nil {
- // s.log.Errorln("GetOffsetTimeV2 ants.Invoke", err)
- // }
- //
- // i += windowInfo.OneStep
- // index++
- // }
- // wg.Wait()
- //
- // return &outMatchInfo, nil
- //}
- //
- //func (s *SubTimelineFixer) calcMeanAndSDV2(startDiffTimeList stat.Float64Slice, tmpStartDiffTime []float64) FixResult {
- //
- // oldMean := stat.Mean(startDiffTimeList)
- // oldSd := stat.Sd(startDiffTimeList)
- // newMean := MinValue
- // newSd := MinValue
- // per := 1.0
- //
- // if len(tmpStartDiffTime) < 3 {
- // return FixResult{
- // 0,
- // 0,
- // oldMean,
- // oldSd,
- // oldMean,
- // oldSd,
- // per,
- // false,
- // make([]MatchWindowInfo, 0),
- // }
- // }
- //
- // // 如果 SD 较大的时候才需要剔除
- // if oldSd > 0.1 {
- // var outliersMap = make(map[float64]int, 0)
- // outliers, _, _ := tukey.Outliers(0.3, tmpStartDiffTime)
- // for _, outlier := range outliers {
- // outliersMap[outlier] = 0
- // }
- // var newStartDiffTimeList = make([]float64, 0)
- // for _, f := range tmpStartDiffTime {
- //
- // _, ok := outliersMap[f]
- // if ok == true {
- // continue
- // }
- //
- // newStartDiffTimeList = append(newStartDiffTimeList, f)
- // }
- //
- // orgLen := startDiffTimeList.Len()
- // startDiffTimeList = make(stat.Float64Slice, 0)
- // for _, f := range newStartDiffTimeList {
- // startDiffTimeList = append(startDiffTimeList, f)
- // }
- // newLen := startDiffTimeList.Len()
- //
- // per = float64(newLen) / float64(orgLen)
- //
- // newMean = stat.Mean(startDiffTimeList)
- // newSd = stat.Sd(startDiffTimeList)
- // }
- //
- // if my_util.IsEqual(newMean, MinValue) == true {
- // newMean = oldMean
- // }
- // if my_util.IsEqual(newSd, MinValue) == true {
- // newSd = oldSd
- // }
- // return FixResult{
- // 0,
- // 0,
- // oldMean,
- // oldSd,
- // newMean,
- // newSd,
- // per,
- // false,
- // make([]MatchWindowInfo, 0),
- // }
- //}
- //
- //// GetOffsetTimeV3 使用内置的字幕校正外置的字幕时间轴
- //func (s *SubTimelineFixer) GetOffsetTimeV3(infoBase, infoSrc, orgFix *subparser.FileInfo, audioVadList []vad.VADInfo) error {
- //
- // // -------------------------------------------------
- // var bUseSubOrAudioAsBase = true
- // if infoBase == nil && audioVadList != nil {
- // // 使用 音频 来进行匹配
- // bUseSubOrAudioAsBase = false
- // } else if infoBase != nil {
- // // 使用 字幕 来进行匹配
- // bUseSubOrAudioAsBase = true
- // } else {
- // return errors.New("GetOffsetTimeV2 input baseUnit or AudioVad is nil")
- // }
- // // -------------------------------------------------
- // audioFloatList := vad.GetFloatSlice(audioVadList)
- // baseUnitNew, err := sub_helper.GetVADInfoFeatureFromSubNew(infoBase, 0)
- // if err != nil {
- // return err
- // }
- // srcUnitNew, err := sub_helper.GetVADInfoFeatureFromSubNew(infoSrc, 0)
- // if err != nil {
- // return err
- // }
- // /*
- // 上面直接得到所有的输入源,都是完整的一个文件,字幕 or 音频
- // 然后根据字幕文件每一个对白进行匹配,这里就使用 V2_FrontAndEndPerSrc 进行字幕的选择,不打算从第一句话开始
- // 那么假如 一共有 100 句话,V2_FrontAndEndPerSrc 是 0.2,那么就是从 20 - 80 句话进行匹配计算
- // 然后 < 20 的就继承 20 的偏移,> 80 的就继承 80 的偏移即可
- // 那么现在就需要从对白中开始遍历
- // */
- // fffAligner := NewFFTAligner(DefaultMaxOffsetSeconds, SampleRate)
- // err2, done := s.caleOne(0.1, srcUnitNew, fffAligner, baseUnitNew)
- // if done {
- // return err2
- // }
- // err2, done = s.caleOne(0.2, srcUnitNew, fffAligner, baseUnitNew)
- // if done {
- // return err2
- // }
- //
- // skipSubLen := int(float64(len(infoSrc.DialoguesFilter)) * s.FixerConfig.V2_FrontAndEndPerSrc)
- //
- // sort.Sort(subparser.OneDialogueByStartTime(infoSrc.DialoguesFilter))
- // sort.Sort(subparser.OneDialogueByStartTime(orgFix.DialoguesFilter))
- //
- // for i := 0; i < len(infoSrc.DialoguesFilter); i++ {
- //
- // // 得到的是真实的时间
- // srcOneDialogueNow := infoSrc.DialoguesFilter[i]
- // srcTimeStartNow, err := my_util.ParseTime(srcOneDialogueNow.StartTime)
- // if err != nil {
- // return err
- // }
- // orgFixOneDialogueNow := orgFix.DialoguesFilter[i]
- // orgFixTimeStartNow, err := my_util.ParseTime(orgFixOneDialogueNow.StartTime)
- // if err != nil {
- // return err
- // }
- //
- // println("Index:", i, "srcTimeStartOrg:", srcTimeStartNow.Format("15:04:05.000"),
- // "src-fix-offset:", my_util.Time2SecondNumber(orgFixTimeStartNow)-my_util.Time2SecondNumber(srcTimeStartNow))
- // }
- // println("------------------")
- // for i := skipSubLen; i < len(infoSrc.DialoguesFilter)-skipSubLen-1; i++ {
- //
- // var bok = false
- // var nowBaseStartTime = 0.0
- // var offsetIndex = 0
- // var score = 0.0
- // const next = 20
- // const secondRange = 45
- // // -------------------------------------------------
- // srcOneDialogueNow := infoSrc.DialoguesFilter[i]
- // iNext := i + next
- // if iNext >= len(infoSrc.DialoguesFilter)-skipSubLen-1 {
- // iNext = len(infoSrc.DialoguesFilter) - skipSubLen - 1
- // }
- // srcOneDialogueNext := infoSrc.DialoguesFilter[iNext]
- // // 得到的是真实的时间
- // srcTimeStartNow, err := my_util.ParseTime(srcOneDialogueNow.StartTime)
- // if err != nil {
- // return err
- // }
- // srcTimeEndNext, err := my_util.ParseTime(srcOneDialogueNext.EndTime)
- // if err != nil {
- // return err
- // }
- // orgFixOneDialogueNow := orgFix.DialoguesFilter[i]
- // orgFixTimeStartNow, err := my_util.ParseTime(orgFixOneDialogueNow.StartTime)
- // if err != nil {
- // return err
- // }
- // // -------------------------------------------------
- // // 需要转换为 VAD 的对应 Index,需要减去 baseTime,然后根据 10ms 进行计算
- // // -------------------------------------------------
- // // Src
- // srcStartOffsetTimeNow := srcUnitNew.RealTimeToOffsetTime(srcTimeStartNow)
- // srcStartTimeVADIndexNow := int(my_util.Time2SecondNumber(srcStartOffsetTimeNow) * 100)
- //
- // srcEndOffsetTimeNext := srcUnitNew.RealTimeToOffsetTime(srcTimeEndNext)
- // srcEndTimeVADIndexNext := int(my_util.Time2SecondNumber(srcEndOffsetTimeNext) * 100)
- // // -------------------------------------------------
- // if bUseSubOrAudioAsBase == false {
- // // 使用 音频 来进行匹配
- //
- // } else {
- // // 使用 字幕 来进行匹配
- // // -------------------------------------------------
- // // Base
- // baseStartOffsetTimeNow := baseUnitNew.RealTimeToOffsetTime(srcTimeStartNow).Add(-secondRange * time.Second)
- // baseStartTimeVADIndexNow := int(my_util.Time2SecondNumber(baseStartOffsetTimeNow) * 100)
- //
- // baseEndOffsetTimeNext := baseUnitNew.RealTimeToOffsetTime(srcTimeEndNext).Add(secondRange * time.Second)
- // baseEndTimeVADIndexNext := int(my_util.Time2SecondNumber(baseEndOffsetTimeNext) * 100)
- // if baseEndTimeVADIndexNext >= len(baseUnitNew.VADList)-1 {
- // baseEndTimeVADIndexNext = len(baseUnitNew.VADList) - 1
- // }
- // // -------------------------------------------------
- // offsetIndex, score = fffAligner.Fit(baseUnitNew.GetVADFloatSlice()[baseStartTimeVADIndexNow:baseEndTimeVADIndexNext], srcUnitNew.GetVADFloatSlice()[srcStartTimeVADIndexNow:srcEndTimeVADIndexNext])
- // if offsetIndex < 0 {
- // //return nil
- // continue
- // }
- // bok, nowBaseStartTime = baseUnitNew.GetIndexTimeNumber(baseStartTimeVADIndexNow+offsetIndex, true)
- // if bok == false {
- // return nil
- // }
- // }
- // // 需要校正的字幕
- // bok, nowSrcStartTime := srcUnitNew.GetIndexTimeNumber(srcStartTimeVADIndexNow, true)
- // if bok == false {
- // return nil
- // }
- // // 时间差值
- // TimeDiffStartCorrelation := nowBaseStartTime - nowSrcStartTime
- //
- // println("Index:", i, "srcTimeStartOrg:", srcTimeStartNow.Format("15:04:05.000"),
- // "OffsetTime:", TimeDiffStartCorrelation, "Score:", score,
- // "ChangedTime:", srcTimeStartNow.Add(time.Duration(TimeDiffStartCorrelation*1000)*time.Millisecond).Format("15:04:05.000"),
- // "OrgFixTime:", orgFixTimeStartNow.Format("15:04:05.000"),
- // "src-fix-offset:", my_util.Time2SecondNumber(orgFixTimeStartNow)-my_util.Time2SecondNumber(srcTimeStartNow))
- // }
- //
- // //if baseStartTimeVADIndexNow > 3600000 {
- // // baseStartTimeVADIndexNow = 0
- // //}
- //
- // println(len(audioFloatList))
- // println(len(baseUnitNew.VADList))
- // println(len(srcUnitNew.VADList))
- //
- // return nil
- //}
- //
- //func (s *SubTimelineFixer) caleOne(cutPer float64, srcUnitNew *sub_helper.SubUnit, fffAligner *FFTAligner, baseUnitNew *sub_helper.SubUnit) (error, bool) {
- // srcVADLen := len(srcUnitNew.VADList)
- // srcCutStartIndex := int(float64(srcVADLen) * cutPer)
- // offsetIndexAll, scoreAll := fffAligner.Fit(baseUnitNew.GetVADFloatSlice(), srcUnitNew.GetVADFloatSlice()[srcCutStartIndex:srcVADLen-srcCutStartIndex])
- // bok, nowBaseStartTime := baseUnitNew.GetIndexTimeNumber(0+offsetIndexAll, true)
- // if bok == false {
- // return nil, true
- // }
- // // 需要校正的字幕
- // bok, nowSrcStartTime := srcUnitNew.GetIndexTimeNumber(srcCutStartIndex, true)
- // if bok == false {
- // return nil, true
- // }
- // // 时间差值
- // TimeDiffStartCorrelation := nowBaseStartTime - nowSrcStartTime
- // bok, srcIndexCutTime := srcUnitNew.GetIndexTime(srcCutStartIndex, true)
- // if bok == false {
- // return nil, true
- // }
- // println(srcIndexCutTime.Format("15:04:05.000"), TimeDiffStartCorrelation, scoreAll)
- // return nil, false
- //}
- //
- //const FixMask = "-fix"
- //const MinValue = -9999.0
- //
- //var mutexFixV2 sync.Mutex
|