fixer.go 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  1. package sub_timeline_fixer
  2. //
  3. //import (
  4. // "errors"
  5. // "fmt"
  6. // "github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
  7. // "github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
  8. // "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
  9. // "github.com/allanpk716/ChineseSubFinder/internal/pkg/vad"
  10. // "github.com/allanpk716/ChineseSubFinder/internal/types/sub_timeline_fiexer"
  11. // "github.com/allanpk716/ChineseSubFinder/internal/types/subparser"
  12. // "github.com/emirpasic/gods/maps/treemap"
  13. // "github.com/emirpasic/gods/utils"
  14. // "github.com/go-echarts/go-echarts/v2/opts"
  15. // "github.com/grd/stat"
  16. // "github.com/james-bowman/nlp/measures/pairwise"
  17. // "github.com/mndrix/tukey"
  18. // "github.com/panjf2000/ants/v2"
  19. // "golang.org/x/net/context"
  20. // "gonum.org/v1/gonum/mat"
  21. // "math"
  22. // "os"
  23. // "sort"
  24. // "strings"
  25. // "sync"
  26. // "time"
  27. //)
  28. //
  29. //type SubTimelineFixer struct {
  30. // log *logrus.Logger
  31. // FixerConfig sub_timeline_fiexer.SubTimelineFixerConfig
  32. //}
  33. //
  34. //func NewSubTimelineFixer(log *logrus.Logger, fixerConfig sub_timeline_fiexer.SubTimelineFixerConfig) *SubTimelineFixer {
  35. // return &SubTimelineFixer{
  36. // log: log,
  37. // FixerConfig: fixerConfig,
  38. // }
  39. //}
  40. //
  41. //// StopWordCounter 停止词统计
  42. //func (s *SubTimelineFixer) StopWordCounter(inString string, per int) []string {
  43. // statisticTimes := make(map[string]int)
  44. // wordsLength := strings.Fields(inString)
  45. //
  46. // for counts, word := range wordsLength {
  47. // // 判断key是否存在,这个word是字符串,这个counts是统计的word的次数。
  48. // word, ok := statisticTimes[word]
  49. // if ok {
  50. // word = word
  51. // statisticTimes[wordsLength[counts]] = statisticTimes[wordsLength[counts]] + 1
  52. // } else {
  53. // statisticTimes[wordsLength[counts]] = 1
  54. // }
  55. // }
  56. //
  57. // stopWords := make([]string, 0)
  58. // mapByValue := sortMapByValue(statisticTimes)
  59. //
  60. // breakIndex := len(mapByValue) * per / 100
  61. // for index, wordInfo := range mapByValue {
  62. // if index > breakIndex {
  63. // break
  64. // }
  65. // stopWords = append(stopWords, wordInfo.Name)
  66. // }
  67. //
  68. // return stopWords
  69. //}
  70. //
  71. //// FixSubTimelineOneOffsetTime 校正整个字幕文件的时间轴,适用于一个偏移值的情况
  72. //func (s *SubTimelineFixer) FixSubTimelineOneOffsetTime(infoSrc *subparser.FileInfo, inOffsetTime float64, desSaveSubFileFullPath string) (string, error) {
  73. //
  74. // /*
  75. // 从解析的实例中,正常来说是可以匹配出所有的 Dialogue 对话的 Start 和 End time 的信息
  76. // 然后找到对应的字幕的文件,进行文件内容的替换来做时间轴的校正
  77. // */
  78. // // 偏移时间
  79. // offsetTime := time.Duration(inOffsetTime*1000) * time.Millisecond
  80. // fixContent := infoSrc.Content
  81. // /*
  82. // 这里进行时间转字符串的时候有一点比较特殊
  83. // 正常来说输出的格式是类似 15:04:05.00
  84. // 那么有个问题,字幕的时间格式是 0:00:12.00, 小时,是个数,除非有跨度到 20 小时的视频,不然小时就应该是个数
  85. // 这就需要一个额外的函数去处理这些情况
  86. // */
  87. // timeFormat := infoSrc.GetTimeFormat()
  88. // for _, srcOneDialogue := range infoSrc.Dialogues {
  89. //
  90. // timeStart, err := my_util.ParseTime(srcOneDialogue.StartTime)
  91. // if err != nil {
  92. // return "", err
  93. // }
  94. // timeEnd, err := my_util.ParseTime(srcOneDialogue.EndTime)
  95. // if err != nil {
  96. // return "", err
  97. // }
  98. //
  99. // fixTimeStart := timeStart.Add(offsetTime)
  100. // fixTimeEnd := timeEnd.Add(offsetTime)
  101. //
  102. // fixContent = strings.ReplaceAll(fixContent, srcOneDialogue.StartTime, my_util.Time2SubTimeString(fixTimeStart, timeFormat))
  103. // fixContent = strings.ReplaceAll(fixContent, srcOneDialogue.EndTime, my_util.Time2SubTimeString(fixTimeEnd, timeFormat))
  104. // }
  105. //
  106. // dstFile, err := os.Create(desSaveSubFileFullPath)
  107. // if err != nil {
  108. // return "", err
  109. // }
  110. // defer func() {
  111. // _ = dstFile.Close()
  112. // }()
  113. // _, err = dstFile.WriteString(fixContent)
  114. // if err != nil {
  115. // return "", err
  116. // }
  117. // return fixContent, nil
  118. //}
  119. //
  120. //// FixSubTimelineByFixResults V2 专用的时间校正函数
  121. //func (s SubTimelineFixer) FixSubTimelineByFixResults(infoSrc *subparser.FileInfo, srcUnitNew *sub_helper.SubUnit, fixedResults []FixResult, desSaveSubFileFullPath string) (string, error) {
  122. //
  123. // startTime := srcUnitNew.GetStartTime(true)
  124. // startTimeBaseDouble := my_util.Time2SecondNumber(startTime)
  125. // /*
  126. // 这里拿到的 fixedResults ,是进行过 V2_FrontAndEndPerSrc 头尾去除
  127. // 那么调整目标字幕的时候,需要考虑截取掉的部分也要算进去
  128. // */
  129. // /*
  130. // 从解析的实例中,正常来说是可以匹配出所有的 Dialogue 对话的 Start 和 End time 的信息
  131. // 然后找到对应的字幕的文件,进行文件内容的替换来做时间轴的校正
  132. // */
  133. // fixContent := infoSrc.Content
  134. // /*
  135. // 这里进行时间转字符串的时候有一点比较特殊
  136. // 正常来说输出的格式是类似 15:04:05.00
  137. // 那么有个问题,字幕的时间格式是 0:00:12.00, 小时,是个数,除非有跨度到 20 小时的视频,不然小时就应该是个数
  138. // 这就需要一个额外的函数去处理这些情况
  139. // */
  140. // timeFormat := infoSrc.GetTimeFormat()
  141. // cacheIndex := 0
  142. // /*
  143. // 这里的理想情况是 Dialogues,每一句话都是递增的对白时间
  144. // 但是实际情况可能是,前面几个对白是特效、音乐的备注,那么他们的跨度可以很大
  145. // 然后才到正常的对话对白,这样就出现不是递增的时间对白情况
  146. // 那么就需要对 Dialogues 进行排序,然后再进行处理
  147. // */
  148. // sort.Sort(subparser.OneDialogueByStartTime(infoSrc.Dialogues))
  149. //
  150. // for index, srcOneDialogue := range infoSrc.Dialogues {
  151. //
  152. // timeStart, err := my_util.ParseTime(srcOneDialogue.StartTime)
  153. // if err != nil {
  154. // return "", err
  155. // }
  156. // timeEnd, err := my_util.ParseTime(srcOneDialogue.EndTime)
  157. // if err != nil {
  158. // return "", err
  159. // }
  160. //
  161. // inOffsetTime := 0.0
  162. // orgStartTimeDouble := my_util.Time2SecondNumber(timeStart)
  163. // for cacheIndex < len(fixedResults) {
  164. //
  165. // inRange, nowOffsetTime := fixedResults[cacheIndex].InRange(startTimeBaseDouble, orgStartTimeDouble)
  166. // if inRange == false {
  167. // // 大于当前的范围,递增一个区间进行再次的判断
  168. // // 但是需要确定的是,递增出来的这个区间的 Index 是有效的,如果是无效的,那么就使用最后一个区间的偏移时间
  169. // cacheIndex++
  170. // continue
  171. // } else {
  172. // inOffsetTime = nowOffsetTime
  173. // break
  174. // }
  175. // }
  176. // if cacheIndex >= len(fixedResults) {
  177. // // 下一个区间的 Index 已经越界了,那么就使用最后一个区间的偏移
  178. // inOffsetTime = fixedResults[len(fixedResults)-1].NewMean
  179. // }
  180. // // 偏移时间
  181. // println(index, inOffsetTime)
  182. // offsetTime := time.Duration(inOffsetTime*1000) * time.Millisecond
  183. // fixTimeStart := timeStart.Add(offsetTime)
  184. // fixTimeEnd := timeEnd.Add(offsetTime)
  185. //
  186. // fixContent = strings.ReplaceAll(fixContent, srcOneDialogue.StartTime, "Index:"+fmt.Sprintf("%d-", index)+my_util.Time2SubTimeString(fixTimeStart, timeFormat))
  187. // fixContent = strings.ReplaceAll(fixContent, srcOneDialogue.EndTime, my_util.Time2SubTimeString(fixTimeEnd, timeFormat))
  188. // }
  189. //
  190. // dstFile, err := os.Create(desSaveSubFileFullPath)
  191. // if err != nil {
  192. // return "", err
  193. // }
  194. // defer func() {
  195. // _ = dstFile.Close()
  196. // }()
  197. // _, err = dstFile.WriteString(fixContent)
  198. // if err != nil {
  199. // return "", err
  200. // }
  201. // return fixContent, nil
  202. //}
  203. //
  204. ///*
  205. // 对于 V1 版本的字幕时间轴校正来说,是有特殊的前置要求的
  206. // 1. 视频要有英文字幕
  207. // 2. 外置的字幕必须是中文的双语字幕(简英、繁英)
  208. //*/
  209. //// GetOffsetTimeV1 暂时只支持英文的基准字幕,源字幕必须是双语中英字幕
  210. //func (s *SubTimelineFixer) GetOffsetTimeV1(infoBase, infoSrc *subparser.FileInfo, staticLineFileSavePath string, debugInfoFileSavePath string) (bool, float64, float64, error) {
  211. //
  212. // var debugInfos = make([]string, 0)
  213. // // 构建基准语料库,目前阶段只需要考虑是 En 的就行了
  214. // var baseCorpus = make([]string, 0)
  215. // var baseDialogueFilterMap = make(map[int]int, 0)
  216. // /*
  217. // 这里原来的写法是所有的 base 的都放进去匹配,这样会带来一些不必要的对白
  218. // 需要剔除空白。那么就需要建立一个转换的字典
  219. // */
  220. // for index, oneDialogueEx := range infoBase.DialoguesFilterEx {
  221. // if oneDialogueEx.EnLine == "" {
  222. // continue
  223. // }
  224. // baseCorpus = append(baseCorpus, oneDialogueEx.EnLine)
  225. // baseDialogueFilterMap[len(baseCorpus)-1] = index
  226. // }
  227. // // 初始化
  228. // pipLine, tfidf, err := NewTFIDF(baseCorpus)
  229. // if err != nil {
  230. // return false, 0, 0, err
  231. // }
  232. //
  233. // /*
  234. // 确认两个字幕间的偏移,暂定的方案是两边都连续匹配上 5 个索引,再抽取一个对话的时间进行修正计算
  235. // */
  236. // maxCompareDialogue := s.FixerConfig.V1_MaxCompareDialogue
  237. // // 基线的长度
  238. // _, docsLength := tfidf.Dims()
  239. // var matchIndexList = make([]MatchIndex, 0)
  240. // sc := NewSubCompare(maxCompareDialogue)
  241. // // 开始比较相似度,默认认为是 Ch_en 就行了
  242. // for srcIndex := 0; srcIndex < len(infoSrc.DialoguesFilterEx); {
  243. //
  244. // srcOneDialogueEx := infoSrc.DialoguesFilterEx[srcIndex]
  245. // // 这里只考虑 英文 的语言
  246. // if srcOneDialogueEx.EnLine == "" {
  247. // srcIndex++
  248. // continue
  249. // }
  250. // // run the query through the same pipeline that was fitted to the corpus and
  251. // // to project it into the same dimensional space
  252. // queryVector, err := pipLine.Transform(srcOneDialogueEx.EnLine)
  253. // if err != nil {
  254. // return false, 0, 0, err
  255. // }
  256. // // iterate over document feature vectors (columns) in the LSI matrix and compare
  257. // // with the query vector for similarity. Similarity is determined by the difference
  258. // // between the angles of the vectors known as the cosine similarity
  259. // highestSimilarity := -1.0
  260. // // 匹配上的基准的索引
  261. // var baseIndex int
  262. // // 这里理论上需要把所有的基线遍历一次,但是,一般来说,两个字幕不可能差距在 50 行
  263. // // 这样的好处是有助于提高搜索的性能
  264. // // 那么就以当前的 src 的位置,向前、向后各 50 来遍历
  265. // nowMaxScanLength := srcIndex + 50
  266. // nowMinScanLength := srcIndex - 50
  267. // if nowMinScanLength < 0 {
  268. // nowMinScanLength = 0
  269. // }
  270. // if nowMaxScanLength > docsLength {
  271. // nowMaxScanLength = docsLength
  272. // }
  273. // for i := nowMinScanLength; i < nowMaxScanLength; i++ {
  274. // similarity := pairwise.CosineSimilarity(queryVector.(mat.ColViewer).ColView(0), tfidf.(mat.ColViewer).ColView(i))
  275. // if similarity > highestSimilarity {
  276. // baseIndex = i
  277. // highestSimilarity = similarity
  278. // }
  279. // }
  280. //
  281. // startBaseIndex, startSrcIndex := sc.GetStartIndex()
  282. // if sc.Add(baseIndex, srcIndex) == false {
  283. // sc.Clear()
  284. // srcIndex = startSrcIndex + 1
  285. // continue
  286. // //sc.Add(baseIndex, srcIndex)
  287. // }
  288. // if sc.Check() == false {
  289. // srcIndex++
  290. // continue
  291. // } else {
  292. // sc.Clear()
  293. // }
  294. //
  295. // matchIndexList = append(matchIndexList, MatchIndex{
  296. // BaseNowIndex: startBaseIndex,
  297. // //BaseNowIndex: baseDialogueFilterMap[startBaseIndex],
  298. // SrcNowIndex: startSrcIndex,
  299. // Similarity: highestSimilarity,
  300. // })
  301. //
  302. // //println(fmt.Sprintf("Similarity: %f Base[%d] %s-%s '%s' <--> Src[%d] %s-%s '%s'",
  303. // // highestSimilarity,
  304. // // baseIndex, infoBase.DialoguesFilterEx[baseIndex].relativelyStartTime, infoBase.DialoguesFilterEx[baseIndex].relativelyEndTime, baseCorpus[baseIndex],
  305. // // srcIndex, srcOneDialogueEx.relativelyStartTime, srcOneDialogueEx.relativelyEndTime, srcOneDialogueEx.EnLine))
  306. //
  307. // srcIndex++
  308. // }
  309. //
  310. // var startDiffTimeLineData = make([]opts.LineData, 0)
  311. // var endDiffTimeLineData = make([]opts.LineData, 0)
  312. // var tmpStartDiffTime = make([]float64, 0)
  313. // var tmpEndDiffTime = make([]float64, 0)
  314. // var startDiffTimeList = make(stat.Float64Slice, 0)
  315. // var endDiffTimeList = make(stat.Float64Slice, 0)
  316. // var xAxis = make([]string, 0)
  317. // // 上面找出了连续匹配 maxCompareDialogue:N 次的字幕语句块
  318. // // 求出平均时间偏移
  319. // for mIndex, matchIndexItem := range matchIndexList {
  320. //
  321. // for i := 0; i < maxCompareDialogue; i++ {
  322. // // 这里会统计连续的这 5 句话的时间差
  323. // //tmpBaseIndex := matchIndexItem.BaseNowIndex + i
  324. // tmpBaseIndex := baseDialogueFilterMap[matchIndexItem.BaseNowIndex+i]
  325. // tmpSrcIndex := matchIndexItem.SrcNowIndex + i
  326. //
  327. // baseTimeStart, err := my_util.ParseTime(infoBase.DialoguesFilterEx[tmpBaseIndex].StartTime)
  328. // if err != nil {
  329. // return false, 0, 0, err
  330. // }
  331. // baseTimeEnd, err := my_util.ParseTime(infoBase.DialoguesFilterEx[tmpBaseIndex].EndTime)
  332. // if err != nil {
  333. // return false, 0, 0, err
  334. // }
  335. // srtTimeStart, err := my_util.ParseTime(infoSrc.DialoguesFilterEx[tmpSrcIndex].StartTime)
  336. // if err != nil {
  337. // return false, 0, 0, err
  338. // }
  339. // srtTimeEnd, err := my_util.ParseTime(infoSrc.DialoguesFilterEx[tmpSrcIndex].EndTime)
  340. // if err != nil {
  341. // return false, 0, 0, err
  342. // }
  343. //
  344. // TimeDiffStart := baseTimeStart.Sub(srtTimeStart)
  345. // TimeDiffEnd := baseTimeEnd.Sub(srtTimeEnd)
  346. //
  347. // startDiffTimeLineData = append(startDiffTimeLineData, opts.LineData{Value: TimeDiffStart.Seconds()})
  348. // endDiffTimeLineData = append(endDiffTimeLineData, opts.LineData{Value: TimeDiffEnd.Seconds()})
  349. //
  350. // tmpStartDiffTime = append(tmpStartDiffTime, TimeDiffStart.Seconds())
  351. // tmpEndDiffTime = append(tmpEndDiffTime, TimeDiffEnd.Seconds())
  352. //
  353. // startDiffTimeList = append(startDiffTimeList, TimeDiffStart.Seconds())
  354. // endDiffTimeList = append(endDiffTimeList, TimeDiffEnd.Seconds())
  355. //
  356. // xAxis = append(xAxis, fmt.Sprintf("%d_%d", mIndex, i))
  357. //
  358. // debugInfos = append(debugInfos, "bs "+infoBase.DialoguesFilterEx[tmpBaseIndex].StartTime+" <-> "+infoBase.DialoguesFilterEx[tmpBaseIndex].EndTime)
  359. // debugInfos = append(debugInfos, "sc "+infoSrc.DialoguesFilterEx[tmpSrcIndex].StartTime+" <-> "+infoSrc.DialoguesFilterEx[tmpSrcIndex].EndTime)
  360. // debugInfos = append(debugInfos, "StartDiffTime: "+fmt.Sprintf("%f", TimeDiffStart.Seconds()))
  361. // //println(fmt.Sprintf("Diff Start-End: %s - %s Base[%d] %s-%s '%s' <--> Src[%d] %s-%s '%s'",
  362. // // TimeDiffStart, TimeDiffEnd,
  363. // // tmpBaseIndex, infoBase.DialoguesFilterEx[tmpBaseIndex].relativelyStartTime, infoBase.DialoguesFilterEx[tmpBaseIndex].relativelyEndTime, infoBase.DialoguesFilterEx[tmpBaseIndex].EnLine,
  364. // // tmpSrcIndex, infoSrc.DialoguesFilterEx[tmpSrcIndex].relativelyStartTime, infoSrc.DialoguesFilterEx[tmpSrcIndex].relativelyEndTime, infoSrc.DialoguesFilterEx[tmpSrcIndex].EnLine))
  365. // }
  366. // debugInfos = append(debugInfos, "---------------------------------------------")
  367. // //println("---------------------------------------------")
  368. // }
  369. //
  370. // oldMean := stat.Mean(startDiffTimeList)
  371. // oldSd := stat.Sd(startDiffTimeList)
  372. // newMean := -1.0
  373. // newSd := -1.0
  374. // per := 1.0
  375. //
  376. // // 如果 SD 较大的时候才需要剔除
  377. // if oldSd > 0.1 {
  378. // var outliersMap = make(map[float64]int, 0)
  379. // outliers, _, _ := tukey.Outliers(0.3, tmpStartDiffTime)
  380. // for _, outlier := range outliers {
  381. // outliersMap[outlier] = 0
  382. // }
  383. // var newStartDiffTimeList = make([]float64, 0)
  384. // for _, f := range tmpStartDiffTime {
  385. //
  386. // _, ok := outliersMap[f]
  387. // if ok == true {
  388. // continue
  389. // }
  390. //
  391. // newStartDiffTimeList = append(newStartDiffTimeList, f)
  392. // }
  393. //
  394. // orgLen := startDiffTimeList.Len()
  395. // startDiffTimeList = make(stat.Float64Slice, 0)
  396. // for _, f := range newStartDiffTimeList {
  397. // startDiffTimeList = append(startDiffTimeList, f)
  398. // }
  399. // newLen := startDiffTimeList.Len()
  400. //
  401. // per = float64(newLen) / float64(orgLen)
  402. //
  403. // newMean = stat.Mean(startDiffTimeList)
  404. // newSd = stat.Sd(startDiffTimeList)
  405. // }
  406. //
  407. // if newMean == -1.0 {
  408. // newMean = oldMean
  409. // }
  410. // if newSd == -1.0 {
  411. // newSd = oldSd
  412. // }
  413. //
  414. // // 不为空的时候,生成调试文件
  415. // if staticLineFileSavePath != "" {
  416. // //staticLineFileSavePath = "bar.html"
  417. // err = SaveStaticLineV1(staticLineFileSavePath, infoBase.Name, infoSrc.Name,
  418. // per, oldMean, oldSd, newMean, newSd, xAxis,
  419. // startDiffTimeLineData, endDiffTimeLineData)
  420. // if err != nil {
  421. // return false, 0, 0, err
  422. // }
  423. // }
  424. //
  425. // // 跳过的逻辑是 mean 是 0 ,那么现在如果判断有问题,缓存的调试文件继续生成,然后强制返回 0 来跳过后续的逻辑
  426. // // 这里需要考虑,找到的连续 5 句话匹配的有多少句,占比整体所有的 Dialogue 是多少,太低也需要跳过
  427. // matchIndexLineCount := len(matchIndexList) * maxCompareDialogue
  428. // //perMatch := float64(matchIndexLineCount) / float64(len(infoSrc.DialoguesFilterEx))
  429. // perMatch := float64(matchIndexLineCount) / float64(len(baseCorpus))
  430. // if perMatch < s.FixerConfig.V1_MinMatchedPercent {
  431. // 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)
  432. //
  433. // debugInfos = append(debugInfos, tmpContent)
  434. //
  435. // s.log.Infoln(tmpContent)
  436. // } else {
  437. // tmpContent := infoSrc.Name + fmt.Sprintf(" Sequence match %d dialogues,", s.FixerConfig.V1_MaxCompareDialogue) + fmt.Sprintf(" %f%% ", perMatch*100)
  438. //
  439. // debugInfos = append(debugInfos, tmpContent)
  440. //
  441. // s.log.Infoln(tmpContent)
  442. // }
  443. //
  444. // // 输出调试的匹配时间轴信息的列表
  445. // if debugInfoFileSavePath != "" {
  446. // err = my_util.WriteStrings2File(debugInfoFileSavePath, debugInfos)
  447. // if err != nil {
  448. // return false, 0, 0, err
  449. // }
  450. // }
  451. // // 虽然有条件判断是认为有问题的,但是返回值还是要填写除去的
  452. // if perMatch < s.FixerConfig.V1_MinMatchedPercent {
  453. // return false, newMean, newSd, nil
  454. // }
  455. //
  456. // return true, newMean, newSd, nil
  457. //}
  458. //
  459. //// GetOffsetTimeV2 使用内置的字幕校正外置的字幕时间轴
  460. //func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit, audioVadList []vad.VADInfo) (bool, []FixResult, error) {
  461. //
  462. // // -------------------------------------------------
  463. // /*
  464. // 开始针对对白单元进行匹配
  465. // 下面的逻辑需要参考 FFT识别流程.jpg 这个图示来理解
  466. // 实际实现的时候,会在上述 srcUnit 上,做一个滑动窗口来做匹配,80% 是窗口,20% 用于移动
  467. // 步长固定在 10 步
  468. // */
  469. // audioFloatList := vad.GetFloatSlice(audioVadList)
  470. //
  471. // srcVADLen := len(srcUnit.VADList)
  472. // // 滑动窗口的长度
  473. // srcWindowLen := int(float64(srcVADLen) * s.FixerConfig.V2_WindowMatchPer)
  474. // // 划分为 4 个区域,每一个部分的长度
  475. // const parts = 10
  476. // perPartLen := srcVADLen / parts
  477. // matchedInfos := make([]MatchInfo, 0)
  478. //
  479. // subVADBlockInfos := make([]SubVADBlockInfo, 0)
  480. // for i := 0; i < parts; i++ {
  481. //
  482. // // 滑动窗体的起始 Index
  483. // srcSlideStartIndex := i * perPartLen
  484. // // 滑动的距离
  485. // srcSlideLen := perPartLen
  486. // // 一步的长度
  487. // oneStep := perPartLen / s.FixerConfig.V2_CompareParts
  488. // if srcSlideLen <= 0 {
  489. // srcSlideLen = 1
  490. // }
  491. // if oneStep <= 0 {
  492. // oneStep = 1
  493. // }
  494. // // -------------------------------------------------
  495. // windowInfo := WindowInfo{
  496. // BaseAudioFloatList: audioFloatList,
  497. // BaseUnit: baseUnit,
  498. // SrcUnit: srcUnit,
  499. // MatchedTimes: 0,
  500. // SrcWindowLen: srcWindowLen,
  501. // SrcSlideStartIndex: srcSlideStartIndex,
  502. // SrcSlideLen: srcSlideLen,
  503. // OneStep: oneStep,
  504. // }
  505. // subVADBlockInfos = append(subVADBlockInfos, SubVADBlockInfo{
  506. // Index: i,
  507. // StartIndex: srcSlideStartIndex,
  508. // EndIndex: srcSlideStartIndex + srcSlideLen,
  509. // })
  510. // // 实际 FFT 的匹配逻辑函数
  511. // // 时间轴差值数组
  512. // matchInfo, err := s.slidingWindowProcessorV2(&windowInfo)
  513. // if err != nil {
  514. // return false, nil, err
  515. // }
  516. //
  517. // matchedInfos = append(matchedInfos, *matchInfo)
  518. // }
  519. //
  520. // fixedResults := make([]FixResult, 0)
  521. // sdLessCount := 0
  522. // // 这里的是 matchedInfos 是顺序的
  523. // for index, matchInfo := range matchedInfos {
  524. //
  525. // s.log.Infoln(index, "------------------------------------")
  526. // outCorrelationFixResult := s.calcMeanAndSDV2(matchInfo.StartDiffTimeListEx, matchInfo.StartDiffTimeList)
  527. // s.log.Infoln(fmt.Sprintf("FFTAligner Old Mean: %v SD: %f Per: %v", outCorrelationFixResult.OldMean, outCorrelationFixResult.OldSD, outCorrelationFixResult.Per))
  528. // s.log.Infoln(fmt.Sprintf("FFTAligner New Mean: %v SD: %f Per: %v", outCorrelationFixResult.NewMean, outCorrelationFixResult.NewSD, outCorrelationFixResult.Per))
  529. //
  530. // value, indexMax := matchInfo.StartDiffTimeMap.Max()
  531. // s.log.Infoln("FFTAligner Max score:", fmt.Sprintf("%v", value.(float64)), "Time:", fmt.Sprintf("%v", matchInfo.StartDiffTimeList[indexMax.(int)]))
  532. //
  533. // outCorrelationFixResult.StartVADIndex = index * perPartLen
  534. // outCorrelationFixResult.EndVADIndex = index*perPartLen + perPartLen
  535. // fixedResults = append(fixedResults, outCorrelationFixResult)
  536. //
  537. // if outCorrelationFixResult.NewSD < 0.1 {
  538. // sdLessCount++
  539. // }
  540. // }
  541. //
  542. // // 如果 0.1 sd 以下的占比低于 70% 那么就认为字幕匹配失败
  543. // perLess := float64(sdLessCount) / float64(len(matchedInfos))
  544. // if perLess < 0.7 {
  545. // return false, nil, nil
  546. // }
  547. //
  548. // // matchedInfos 与 fixedResults 是对等的关系,fixedResults 中是计算过 Mean 的值,而 matchedInfos 有原始的值
  549. // for i, info := range matchedInfos {
  550. // for j := 0; j < len(info.IndexMatchWindowInfoMap); j++ {
  551. //
  552. // value, bFound := info.IndexMatchWindowInfoMap[j]
  553. // if bFound == false {
  554. // continue
  555. // }
  556. //
  557. // fixedResults[i].MatchWindowInfos = append(fixedResults[i].MatchWindowInfos, value)
  558. // }
  559. // }
  560. // /*
  561. // 如果 outCorrelationFixResult 的 SD > 0.1,那么大概率这个时间轴的值匹配的有问题,需要向左或者向右找一个值进行继承
  562. // -4 0.001
  563. // -4 0.001
  564. // -4 0.001
  565. // -200 0.1
  566. // -4 0.001
  567. // 比如这种情况,那么就需要向左找到 -4 去继承。
  568. // 具体的实现:
  569. // 找到一个 SD > 0.1 的项目,那么就需要从左边和右边同时对比
  570. // 首先是他们的差值要在 0.3s (绝对值)以内,优先往左边找,如果绝对值成立则判断 SD (SD 必须 < 0.1)
  571. // 如果只是 SD 不成立,那么就继续往左,继续判断差值和 SD。
  572. // 如果都找不到合适的,就要回到”起点“,从右开始找,逻辑一样
  573. // 直到没有找到合适的信息,就报错
  574. // */
  575. // // 进行细节的修正
  576. // for index, fixedResult := range fixedResults {
  577. // // SD 大于 0.1 或者是 当前的 NewMean 与上一个点的 NewMean 差值大于 0.3
  578. // if fixedResult.NewSD >= 0.1 || (index > 1 && math.Abs(fixedResult.NewMean-fixedResults[index-1].NewMean) > 0.3) {
  579. // bok, newMean, newSD := s.fixOnePartV2(index, fixedResults)
  580. // if bok == true {
  581. // fixedResults[index].NewMean = newMean
  582. // fixedResults[index].NewSD = newSD
  583. // }
  584. // }
  585. // }
  586. //
  587. // return true, fixedResults, nil
  588. //}
  589. //
  590. //// fixOnePartV2 轻微地跳动可以根据左或者右去微调
  591. //func (s SubTimelineFixer) fixOnePartV2(startIndex int, fixedResults []FixResult) (bool, float64, float64) {
  592. //
  593. // /*
  594. // 找到这样情况的进行修正
  595. // */
  596. // // 先往左
  597. // if startIndex-1 >= 0 {
  598. // // 说明至少可以往左
  599. // // 如果左边的这个值,与当前值超过了 0.3 的绝对差值,那么是不适合的,就需要往右找
  600. // if math.Abs(fixedResults[startIndex-1].NewMean-fixedResults[startIndex].NewMean) < 0.3 {
  601. // // 差值在接受的范围内,那么就使用这个左边的值去校正当前的值
  602. // return true, fixedResults[startIndex-1].NewMean, fixedResults[startIndex-1].NewSD
  603. // }
  604. // }
  605. //
  606. // // 如果上面的理想情况都没有进去,那么就是这个差值很大
  607. // if fixedResults[startIndex].NewSD > 1 {
  608. // // SD 比较大,可能当前的位置是值是错误的,那么直接就使用左边的值
  609. // /*
  610. // -6.3 0.06
  611. // -146.85 243.83
  612. // */
  613. // if startIndex-1 >= 0 {
  614. // return true, fixedResults[startIndex-1].NewMean, fixedResults[startIndex-1].NewSD
  615. // }
  616. // } else {
  617. // // SD 不是很大,可能就是正常的字幕分段的时间轴偏移的 越接处 !
  618. // // 那么需要取,越接处,前三和后三,进行均值计算
  619. // /*
  620. // -6.21
  621. // -6.22
  622. // -6.29 0.06
  623. //
  624. // -7.13 0.14 越接处
  625. //
  626. // -7.32
  627. // -7.31
  628. // -7.44
  629. // */
  630. // left3Mean := 0.0
  631. // right3Mean := 0.0
  632. // // 向左,三个或者三个位置
  633. // if startIndex-3 >= 0 {
  634. // left3Mean = float64(fixedResults[startIndex-1].NewMean+fixedResults[startIndex-2].NewMean+fixedResults[startIndex-3].NewMean) / 3.0
  635. // } else if startIndex-2 >= 0 {
  636. // left3Mean = float64(fixedResults[startIndex-1].NewMean+fixedResults[startIndex-2].NewMean) / 2.0
  637. // } else {
  638. // return false, 0, 0
  639. // }
  640. // // 向右,三个或者三个位置
  641. // if startIndex+3 >= 0 {
  642. // right3Mean = float64(fixedResults[startIndex+1].NewMean+fixedResults[startIndex+2].NewMean+fixedResults[startIndex+3].NewMean) / 3.0
  643. // } else if startIndex+2 >= 0 {
  644. // right3Mean = float64(fixedResults[startIndex+1].NewMean+fixedResults[startIndex+2].NewMean) / 2.0
  645. // } else {
  646. // return false, 0, 0
  647. // }
  648. // // 将这个匹配的段中的子分段的时间轴偏移都进行一次计算,推算出到底是怎么样的配比可以得到这样的偏移结论
  649. // for i, info := range fixedResults[startIndex].MatchWindowInfos {
  650. //
  651. // perPartLen := info.EndVADIndex - info.StartVADIndex
  652. // op := OverParts{}
  653. // // xLen 计算公式见推到公式截图
  654. // xLen := (info.TimeDiffStartCorrelation*float64(perPartLen) - right3Mean*float64(perPartLen)) / (left3Mean - right3Mean)
  655. // yLen := float64(perPartLen) - xLen
  656. //
  657. // op.XLen = xLen
  658. // op.YLen = yLen
  659. // op.XMean = left3Mean
  660. // op.YMean = right3Mean
  661. //
  662. // fixedResults[startIndex].IsOverParts = true
  663. // fixedResults[startIndex].MatchWindowInfos[i].OP = op
  664. // }
  665. //
  666. // return true, fixedResults[startIndex+1].NewMean, fixedResults[startIndex+1].NewSD
  667. // }
  668. //
  669. // return false, 0, 0
  670. //}
  671. //
  672. //// slidingWindowProcessorV2 滑动窗口计算时间轴偏移
  673. //func (s *SubTimelineFixer) slidingWindowProcessorV2(windowInfo *WindowInfo) (*MatchInfo, error) {
  674. //
  675. // // -------------------------------------------------
  676. // var bUseSubOrAudioAsBase = true
  677. // if windowInfo.BaseUnit == nil && windowInfo.BaseAudioFloatList != nil {
  678. // // 使用 音频 来进行匹配
  679. // bUseSubOrAudioAsBase = false
  680. // } else if windowInfo.BaseUnit != nil {
  681. // // 使用 字幕 来进行匹配
  682. // bUseSubOrAudioAsBase = true
  683. // } else {
  684. // return nil, errors.New("GetOffsetTimeV2 input baseUnit or AudioVad is nil")
  685. // }
  686. // // -------------------------------------------------
  687. // outMatchInfo := MatchInfo{
  688. // IndexMatchWindowInfoMap: make(map[int]MatchWindowInfo, 0),
  689. // StartDiffTimeList: make([]float64, 0),
  690. // StartDiffTimeMap: treemap.NewWith(utils.Float64Comparator),
  691. // StartDiffTimeListEx: make(stat.Float64Slice, 0),
  692. // }
  693. // fixFunc := func(i interface{}) error {
  694. // inData := i.(InputData)
  695. // // -------------------------------------------------
  696. // // 开始匹配
  697. // // 这里的对白单元,当前的 Base 进行对比,详细示例见图解。Step 2 中橙色的区域
  698. // fffAligner := NewFFTAligner(DefaultMaxOffsetSeconds, SampleRate)
  699. // var bok = false
  700. // var nowBaseStartTime = 0.0
  701. // var offsetIndex = 0
  702. // var score = 0.0
  703. // srcMaxLen := 0
  704. // // 图解,参考 Step 3
  705. // if bUseSubOrAudioAsBase == false {
  706. // // 使用 音频 来进行匹配
  707. // // 去掉头和尾,具体百分之多少,见 V2_FrontAndEndPerBase
  708. // audioCutLen := int(float64(len(inData.BaseAudioVADList)) * s.FixerConfig.V2_FrontAndEndPerBase)
  709. //
  710. // srcMaxLen = windowInfo.SrcWindowLen + inData.OffsetIndex
  711. // if srcMaxLen >= len(inData.SrcUnit.GetVADFloatSlice()) {
  712. // srcMaxLen = len(inData.SrcUnit.GetVADFloatSlice()) - 1
  713. // }
  714. // offsetIndex, score = fffAligner.Fit(inData.BaseAudioVADList[audioCutLen:len(inData.BaseAudioVADList)-audioCutLen], inData.SrcUnit.GetVADFloatSlice()[inData.OffsetIndex:srcMaxLen])
  715. // realOffsetIndex := offsetIndex + audioCutLen
  716. // if realOffsetIndex < 0 {
  717. // return nil
  718. // }
  719. // // offsetIndex 这里得到的是 10ms 为一个单位的 OffsetIndex
  720. // nowBaseStartTime = vad.GetAudioIndex2Time(realOffsetIndex)
  721. //
  722. // } else {
  723. // // 使用 字幕 来进行匹配
  724. //
  725. // srcMaxLen = inData.OffsetIndex + windowInfo.SrcWindowLen
  726. // if srcMaxLen >= len(inData.SrcUnit.GetVADFloatSlice()) {
  727. // srcMaxLen = len(inData.SrcUnit.GetVADFloatSlice()) - 1
  728. // }
  729. // offsetIndex, score = fffAligner.Fit(inData.BaseUnit.GetVADFloatSlice(), inData.SrcUnit.GetVADFloatSlice()[inData.OffsetIndex:srcMaxLen])
  730. // if offsetIndex < 0 {
  731. // return nil
  732. // }
  733. // bok, nowBaseStartTime = inData.BaseUnit.GetIndexTimeNumber(offsetIndex, true)
  734. // if bok == false {
  735. // return nil
  736. // }
  737. // }
  738. // // 需要校正的字幕
  739. // bok, nowSrcStartTime := inData.SrcUnit.GetIndexTimeNumber(inData.OffsetIndex, true)
  740. // if bok == false {
  741. // return nil
  742. // }
  743. // // 时间差值
  744. // TimeDiffStartCorrelation := nowBaseStartTime - nowSrcStartTime
  745. // s.log.Debugln("------------")
  746. // s.log.Debugln("OffsetTime:", fmt.Sprintf("%v", TimeDiffStartCorrelation),
  747. // "offsetIndex:", offsetIndex,
  748. // "score:", fmt.Sprintf("%v", score))
  749. //
  750. // mutexFixV2.Lock()
  751. // // 这里的未必的顺序的,所以才有 IndexMatchWindowInfoMap 的存在的意义
  752. // outMatchInfo.IndexMatchWindowInfoMap[inData.Index] = MatchWindowInfo{TimeDiffStartCorrelation: TimeDiffStartCorrelation,
  753. // StartVADIndex: inData.OffsetIndex,
  754. // EndVADIndex: srcMaxLen}
  755. // outMatchInfo.StartDiffTimeList = append(outMatchInfo.StartDiffTimeList, TimeDiffStartCorrelation)
  756. // outMatchInfo.StartDiffTimeListEx = append(outMatchInfo.StartDiffTimeListEx, TimeDiffStartCorrelation)
  757. // outMatchInfo.StartDiffTimeMap.Put(score, windowInfo.MatchedTimes)
  758. // windowInfo.MatchedTimes++
  759. // mutexFixV2.Unlock()
  760. // // -------------------------------------------------
  761. // return nil
  762. // }
  763. // // -------------------------------------------------
  764. // antPool, err := ants.NewPoolWithFunc(s.FixerConfig.V2_FixThreads, func(inData interface{}) {
  765. // data := inData.(InputData)
  766. // defer data.Wg.Done()
  767. // ctx, cancel := context.WithTimeout(context.Background(), time.Duration(s.FixerConfig.V2_SubOneUnitProcessTimeOut)*time.Second)
  768. // defer cancel()
  769. //
  770. // done := make(chan error, 1)
  771. // panicChan := make(chan interface{}, 1)
  772. // go func() {
  773. // defer func() {
  774. // if p := recover(); p != nil {
  775. // panicChan <- p
  776. // }
  777. // }()
  778. //
  779. // done <- fixFunc(inData)
  780. // }()
  781. //
  782. // select {
  783. // case err := <-done:
  784. // if err != nil {
  785. // s.log.Errorln("GetOffsetTimeV2.NewPoolWithFunc done with Error", err.Error())
  786. // }
  787. // return
  788. // case p := <-panicChan:
  789. // s.log.Errorln("GetOffsetTimeV2.NewPoolWithFunc got panic", p)
  790. // return
  791. // case <-ctx.Done():
  792. // s.log.Errorln("GetOffsetTimeV2.NewPoolWithFunc got time out", ctx.Err())
  793. // return
  794. // }
  795. // })
  796. // if err != nil {
  797. // return nil, err
  798. // }
  799. // defer antPool.Release()
  800. // // -------------------------------------------------
  801. // wg := sync.WaitGroup{}
  802. // index := 0
  803. // for i := windowInfo.SrcSlideStartIndex; i < windowInfo.SrcSlideStartIndex+windowInfo.SrcSlideLen-1; {
  804. // wg.Add(1)
  805. //
  806. // if bUseSubOrAudioAsBase == true {
  807. // // 使用字幕
  808. // err = antPool.Invoke(InputData{Index: index, BaseUnit: *windowInfo.BaseUnit, SrcUnit: *windowInfo.SrcUnit, OffsetIndex: i, Wg: &wg})
  809. // } else {
  810. // // 使用音频
  811. // err = antPool.Invoke(InputData{Index: index, BaseAudioVADList: windowInfo.BaseAudioFloatList, SrcUnit: *windowInfo.SrcUnit, OffsetIndex: i, Wg: &wg})
  812. // }
  813. //
  814. // if err != nil {
  815. // s.log.Errorln("GetOffsetTimeV2 ants.Invoke", err)
  816. // }
  817. //
  818. // i += windowInfo.OneStep
  819. // index++
  820. // }
  821. // wg.Wait()
  822. //
  823. // return &outMatchInfo, nil
  824. //}
  825. //
  826. //func (s *SubTimelineFixer) calcMeanAndSDV2(startDiffTimeList stat.Float64Slice, tmpStartDiffTime []float64) FixResult {
  827. //
  828. // oldMean := stat.Mean(startDiffTimeList)
  829. // oldSd := stat.Sd(startDiffTimeList)
  830. // newMean := MinValue
  831. // newSd := MinValue
  832. // per := 1.0
  833. //
  834. // if len(tmpStartDiffTime) < 3 {
  835. // return FixResult{
  836. // 0,
  837. // 0,
  838. // oldMean,
  839. // oldSd,
  840. // oldMean,
  841. // oldSd,
  842. // per,
  843. // false,
  844. // make([]MatchWindowInfo, 0),
  845. // }
  846. // }
  847. //
  848. // // 如果 SD 较大的时候才需要剔除
  849. // if oldSd > 0.1 {
  850. // var outliersMap = make(map[float64]int, 0)
  851. // outliers, _, _ := tukey.Outliers(0.3, tmpStartDiffTime)
  852. // for _, outlier := range outliers {
  853. // outliersMap[outlier] = 0
  854. // }
  855. // var newStartDiffTimeList = make([]float64, 0)
  856. // for _, f := range tmpStartDiffTime {
  857. //
  858. // _, ok := outliersMap[f]
  859. // if ok == true {
  860. // continue
  861. // }
  862. //
  863. // newStartDiffTimeList = append(newStartDiffTimeList, f)
  864. // }
  865. //
  866. // orgLen := startDiffTimeList.Len()
  867. // startDiffTimeList = make(stat.Float64Slice, 0)
  868. // for _, f := range newStartDiffTimeList {
  869. // startDiffTimeList = append(startDiffTimeList, f)
  870. // }
  871. // newLen := startDiffTimeList.Len()
  872. //
  873. // per = float64(newLen) / float64(orgLen)
  874. //
  875. // newMean = stat.Mean(startDiffTimeList)
  876. // newSd = stat.Sd(startDiffTimeList)
  877. // }
  878. //
  879. // if my_util.IsEqual(newMean, MinValue) == true {
  880. // newMean = oldMean
  881. // }
  882. // if my_util.IsEqual(newSd, MinValue) == true {
  883. // newSd = oldSd
  884. // }
  885. // return FixResult{
  886. // 0,
  887. // 0,
  888. // oldMean,
  889. // oldSd,
  890. // newMean,
  891. // newSd,
  892. // per,
  893. // false,
  894. // make([]MatchWindowInfo, 0),
  895. // }
  896. //}
  897. //
  898. //// GetOffsetTimeV3 使用内置的字幕校正外置的字幕时间轴
  899. //func (s *SubTimelineFixer) GetOffsetTimeV3(infoBase, infoSrc, orgFix *subparser.FileInfo, audioVadList []vad.VADInfo) error {
  900. //
  901. // // -------------------------------------------------
  902. // var bUseSubOrAudioAsBase = true
  903. // if infoBase == nil && audioVadList != nil {
  904. // // 使用 音频 来进行匹配
  905. // bUseSubOrAudioAsBase = false
  906. // } else if infoBase != nil {
  907. // // 使用 字幕 来进行匹配
  908. // bUseSubOrAudioAsBase = true
  909. // } else {
  910. // return errors.New("GetOffsetTimeV2 input baseUnit or AudioVad is nil")
  911. // }
  912. // // -------------------------------------------------
  913. // audioFloatList := vad.GetFloatSlice(audioVadList)
  914. // baseUnitNew, err := sub_helper.GetVADInfoFeatureFromSubNew(infoBase, 0)
  915. // if err != nil {
  916. // return err
  917. // }
  918. // srcUnitNew, err := sub_helper.GetVADInfoFeatureFromSubNew(infoSrc, 0)
  919. // if err != nil {
  920. // return err
  921. // }
  922. // /*
  923. // 上面直接得到所有的输入源,都是完整的一个文件,字幕 or 音频
  924. // 然后根据字幕文件每一个对白进行匹配,这里就使用 V2_FrontAndEndPerSrc 进行字幕的选择,不打算从第一句话开始
  925. // 那么假如 一共有 100 句话,V2_FrontAndEndPerSrc 是 0.2,那么就是从 20 - 80 句话进行匹配计算
  926. // 然后 < 20 的就继承 20 的偏移,> 80 的就继承 80 的偏移即可
  927. // 那么现在就需要从对白中开始遍历
  928. // */
  929. // fffAligner := NewFFTAligner(DefaultMaxOffsetSeconds, SampleRate)
  930. // err2, done := s.caleOne(0.1, srcUnitNew, fffAligner, baseUnitNew)
  931. // if done {
  932. // return err2
  933. // }
  934. // err2, done = s.caleOne(0.2, srcUnitNew, fffAligner, baseUnitNew)
  935. // if done {
  936. // return err2
  937. // }
  938. //
  939. // skipSubLen := int(float64(len(infoSrc.DialoguesFilter)) * s.FixerConfig.V2_FrontAndEndPerSrc)
  940. //
  941. // sort.Sort(subparser.OneDialogueByStartTime(infoSrc.DialoguesFilter))
  942. // sort.Sort(subparser.OneDialogueByStartTime(orgFix.DialoguesFilter))
  943. //
  944. // for i := 0; i < len(infoSrc.DialoguesFilter); i++ {
  945. //
  946. // // 得到的是真实的时间
  947. // srcOneDialogueNow := infoSrc.DialoguesFilter[i]
  948. // srcTimeStartNow, err := my_util.ParseTime(srcOneDialogueNow.StartTime)
  949. // if err != nil {
  950. // return err
  951. // }
  952. // orgFixOneDialogueNow := orgFix.DialoguesFilter[i]
  953. // orgFixTimeStartNow, err := my_util.ParseTime(orgFixOneDialogueNow.StartTime)
  954. // if err != nil {
  955. // return err
  956. // }
  957. //
  958. // println("Index:", i, "srcTimeStartOrg:", srcTimeStartNow.Format("15:04:05.000"),
  959. // "src-fix-offset:", my_util.Time2SecondNumber(orgFixTimeStartNow)-my_util.Time2SecondNumber(srcTimeStartNow))
  960. // }
  961. // println("------------------")
  962. // for i := skipSubLen; i < len(infoSrc.DialoguesFilter)-skipSubLen-1; i++ {
  963. //
  964. // var bok = false
  965. // var nowBaseStartTime = 0.0
  966. // var offsetIndex = 0
  967. // var score = 0.0
  968. // const next = 20
  969. // const secondRange = 45
  970. // // -------------------------------------------------
  971. // srcOneDialogueNow := infoSrc.DialoguesFilter[i]
  972. // iNext := i + next
  973. // if iNext >= len(infoSrc.DialoguesFilter)-skipSubLen-1 {
  974. // iNext = len(infoSrc.DialoguesFilter) - skipSubLen - 1
  975. // }
  976. // srcOneDialogueNext := infoSrc.DialoguesFilter[iNext]
  977. // // 得到的是真实的时间
  978. // srcTimeStartNow, err := my_util.ParseTime(srcOneDialogueNow.StartTime)
  979. // if err != nil {
  980. // return err
  981. // }
  982. // srcTimeEndNext, err := my_util.ParseTime(srcOneDialogueNext.EndTime)
  983. // if err != nil {
  984. // return err
  985. // }
  986. // orgFixOneDialogueNow := orgFix.DialoguesFilter[i]
  987. // orgFixTimeStartNow, err := my_util.ParseTime(orgFixOneDialogueNow.StartTime)
  988. // if err != nil {
  989. // return err
  990. // }
  991. // // -------------------------------------------------
  992. // // 需要转换为 VAD 的对应 Index,需要减去 baseTime,然后根据 10ms 进行计算
  993. // // -------------------------------------------------
  994. // // Src
  995. // srcStartOffsetTimeNow := srcUnitNew.RealTimeToOffsetTime(srcTimeStartNow)
  996. // srcStartTimeVADIndexNow := int(my_util.Time2SecondNumber(srcStartOffsetTimeNow) * 100)
  997. //
  998. // srcEndOffsetTimeNext := srcUnitNew.RealTimeToOffsetTime(srcTimeEndNext)
  999. // srcEndTimeVADIndexNext := int(my_util.Time2SecondNumber(srcEndOffsetTimeNext) * 100)
  1000. // // -------------------------------------------------
  1001. // if bUseSubOrAudioAsBase == false {
  1002. // // 使用 音频 来进行匹配
  1003. //
  1004. // } else {
  1005. // // 使用 字幕 来进行匹配
  1006. // // -------------------------------------------------
  1007. // // Base
  1008. // baseStartOffsetTimeNow := baseUnitNew.RealTimeToOffsetTime(srcTimeStartNow).Add(-secondRange * time.Second)
  1009. // baseStartTimeVADIndexNow := int(my_util.Time2SecondNumber(baseStartOffsetTimeNow) * 100)
  1010. //
  1011. // baseEndOffsetTimeNext := baseUnitNew.RealTimeToOffsetTime(srcTimeEndNext).Add(secondRange * time.Second)
  1012. // baseEndTimeVADIndexNext := int(my_util.Time2SecondNumber(baseEndOffsetTimeNext) * 100)
  1013. // if baseEndTimeVADIndexNext >= len(baseUnitNew.VADList)-1 {
  1014. // baseEndTimeVADIndexNext = len(baseUnitNew.VADList) - 1
  1015. // }
  1016. // // -------------------------------------------------
  1017. // offsetIndex, score = fffAligner.Fit(baseUnitNew.GetVADFloatSlice()[baseStartTimeVADIndexNow:baseEndTimeVADIndexNext], srcUnitNew.GetVADFloatSlice()[srcStartTimeVADIndexNow:srcEndTimeVADIndexNext])
  1018. // if offsetIndex < 0 {
  1019. // //return nil
  1020. // continue
  1021. // }
  1022. // bok, nowBaseStartTime = baseUnitNew.GetIndexTimeNumber(baseStartTimeVADIndexNow+offsetIndex, true)
  1023. // if bok == false {
  1024. // return nil
  1025. // }
  1026. // }
  1027. // // 需要校正的字幕
  1028. // bok, nowSrcStartTime := srcUnitNew.GetIndexTimeNumber(srcStartTimeVADIndexNow, true)
  1029. // if bok == false {
  1030. // return nil
  1031. // }
  1032. // // 时间差值
  1033. // TimeDiffStartCorrelation := nowBaseStartTime - nowSrcStartTime
  1034. //
  1035. // println("Index:", i, "srcTimeStartOrg:", srcTimeStartNow.Format("15:04:05.000"),
  1036. // "OffsetTime:", TimeDiffStartCorrelation, "Score:", score,
  1037. // "ChangedTime:", srcTimeStartNow.Add(time.Duration(TimeDiffStartCorrelation*1000)*time.Millisecond).Format("15:04:05.000"),
  1038. // "OrgFixTime:", orgFixTimeStartNow.Format("15:04:05.000"),
  1039. // "src-fix-offset:", my_util.Time2SecondNumber(orgFixTimeStartNow)-my_util.Time2SecondNumber(srcTimeStartNow))
  1040. // }
  1041. //
  1042. // //if baseStartTimeVADIndexNow > 3600000 {
  1043. // // baseStartTimeVADIndexNow = 0
  1044. // //}
  1045. //
  1046. // println(len(audioFloatList))
  1047. // println(len(baseUnitNew.VADList))
  1048. // println(len(srcUnitNew.VADList))
  1049. //
  1050. // return nil
  1051. //}
  1052. //
  1053. //func (s *SubTimelineFixer) caleOne(cutPer float64, srcUnitNew *sub_helper.SubUnit, fffAligner *FFTAligner, baseUnitNew *sub_helper.SubUnit) (error, bool) {
  1054. // srcVADLen := len(srcUnitNew.VADList)
  1055. // srcCutStartIndex := int(float64(srcVADLen) * cutPer)
  1056. // offsetIndexAll, scoreAll := fffAligner.Fit(baseUnitNew.GetVADFloatSlice(), srcUnitNew.GetVADFloatSlice()[srcCutStartIndex:srcVADLen-srcCutStartIndex])
  1057. // bok, nowBaseStartTime := baseUnitNew.GetIndexTimeNumber(0+offsetIndexAll, true)
  1058. // if bok == false {
  1059. // return nil, true
  1060. // }
  1061. // // 需要校正的字幕
  1062. // bok, nowSrcStartTime := srcUnitNew.GetIndexTimeNumber(srcCutStartIndex, true)
  1063. // if bok == false {
  1064. // return nil, true
  1065. // }
  1066. // // 时间差值
  1067. // TimeDiffStartCorrelation := nowBaseStartTime - nowSrcStartTime
  1068. // bok, srcIndexCutTime := srcUnitNew.GetIndexTime(srcCutStartIndex, true)
  1069. // if bok == false {
  1070. // return nil, true
  1071. // }
  1072. // println(srcIndexCutTime.Format("15:04:05.000"), TimeDiffStartCorrelation, scoreAll)
  1073. // return nil, false
  1074. //}
  1075. //
  1076. //const FixMask = "-fix"
  1077. //const MinValue = -9999.0
  1078. //
  1079. //var mutexFixV2 sync.Mutex