sub_unit.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package sub_helper
  2. import (
  3. "fmt"
  4. "github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
  5. "github.com/allanpk716/ChineseSubFinder/internal/pkg/vad"
  6. "math"
  7. "time"
  8. )
  9. type SubUnit struct {
  10. baseTime time.Time // 这个是基础的时间,后续需要减去这个,不然与导出的片段字幕去对比会有一个起始时间的偏差
  11. offsetStartTime time.Time // 相对时间,这个时间会减去 baseTime 再存储
  12. offsetEndTime time.Time // 相对时间,这个时间会减去 baseTime 再存储
  13. VADList []vad.VADInfo
  14. subCount int
  15. firstAdd bool
  16. outVADBytes []byte
  17. }
  18. func NewSubUnit() *SubUnit {
  19. return &SubUnit{
  20. VADList: make([]vad.VADInfo, 0),
  21. subCount: 0,
  22. firstAdd: false,
  23. outVADBytes: make([]byte, 0),
  24. }
  25. }
  26. // AddAndInsert 添加一句对白进来,并且填充中间的空白,间隔 10ms
  27. func (s *SubUnit) AddAndInsert(oneSubStartTime, oneSubEndTime time.Time) {
  28. /*
  29. 这里有个比较有意思的细节,字幕拆分到 dialogue 的时候,可能连续的多个 dialogue 是时间轴连续的
  30. 但是实际上的语言就是可以分为几个句子的
  31. 那么,在本函数中,就需要判断插入的时候,与上一句话的时间轴关系,前置无需进行句子的合并
  32. 如果两句话时间轴是连续的(差值为0),那么就要主动修改这一点,采取的方案可以是
  33. 1. 前后各 0.001 秒即可
  34. 2. 后面这一句向后 0.002 秒(暂时优先考虑这个,容易实现)
  35. */
  36. const perWindows = float64(vad.FrameDuration) / 1000
  37. // 不是第一次添加,那么就需要把两句对白中间间隔的 active == false 的插入,插入间隙
  38. if len(s.VADList) > 0 {
  39. nowStartTime := s.RealTimeToOffsetTime(oneSubStartTime)
  40. nowStartOffsetTime := my_util.Time2SecendNumber(nowStartTime)
  41. nowEndOffsetTime := s.GetEndTimeNumber(false)
  42. needAddRange := nowStartOffsetTime - nowEndOffsetTime
  43. if needAddRange == 0 {
  44. // 说明是连续的句子,向后加 0.002 秒
  45. addMore := time.Duration((s.GetEndTimeNumber(true) + 0.002) * math.Pow10(9))
  46. s.VADList = append(s.VADList, *vad.NewVADInfoBase(false, addMore))
  47. // 因为是连续的两句话的时间轴,强制插入了一个点,那么就需要在这句话的 Start 部分向后延迟对应的秒数
  48. oneSubStartTime = oneSubStartTime.Add(time.Duration(0.002 * math.Pow10(9)))
  49. } else {
  50. for i := 0.0; i < needAddRange; {
  51. s.VADList = append(s.VADList, *vad.NewVADInfoBase(false, time.Duration((s.GetEndTimeNumber(true)+i)*math.Pow10(9))))
  52. i += perWindows
  53. }
  54. }
  55. }
  56. if s.firstAdd == false {
  57. // 第一次 Add 需要给 baseTime 赋值
  58. s.baseTime = oneSubStartTime
  59. s.offsetStartTime = s.RealTimeToOffsetTime(oneSubStartTime)
  60. s.firstAdd = true
  61. }
  62. s.offsetEndTime = oneSubEndTime.Add(-my_util.Time2Duration(s.baseTime))
  63. nowStartTime := s.RealTimeToOffsetTime(oneSubStartTime)
  64. nowEndTime := s.RealTimeToOffsetTime(oneSubEndTime)
  65. nowStartOffsetTime := my_util.Time2SecendNumber(nowStartTime)
  66. nowEndOffsetTime := my_util.Time2SecendNumber(nowEndTime)
  67. needAddRange := nowEndOffsetTime - nowStartOffsetTime
  68. for i := 0.0; i < needAddRange; {
  69. s.VADList = append(s.VADList, *vad.NewVADInfoBase(true, time.Duration((my_util.Time2SecendNumber(oneSubStartTime)+i)*math.Pow10(9))))
  70. i += perWindows
  71. }
  72. s.subCount++
  73. }
  74. // GetDialogueCount 获取这个对白单元由几个对话
  75. func (s SubUnit) GetDialogueCount() int {
  76. return s.subCount
  77. }
  78. // GetVADSlice 获取 VAD 的 byte 数组信息
  79. func (s *SubUnit) GetVADSlice() []byte {
  80. if len(s.outVADBytes) != len(s.VADList) {
  81. s.outVADBytes = make([]byte, len(s.VADList))
  82. for i := 0; i < len(s.VADList); i++ {
  83. if s.VADList[i].Active == true {
  84. s.outVADBytes[i] = 1
  85. } else {
  86. s.outVADBytes[i] = 0
  87. }
  88. }
  89. }
  90. return s.outVADBytes
  91. }
  92. // GetStartTimeNumber 获取这个单元的起始时间,单位是秒
  93. func (s SubUnit) GetStartTimeNumber(realOrOffsetTime bool) float64 {
  94. return my_util.Time2SecendNumber(s.GetStartTime(realOrOffsetTime))
  95. }
  96. // GetStartTime 获取这个单元的起始时间
  97. func (s SubUnit) GetStartTime(realOrOffsetTime bool) time.Time {
  98. if realOrOffsetTime == true {
  99. return s.offsetStartTime.Add(my_util.Time2Duration(s.baseTime))
  100. } else {
  101. return s.offsetStartTime
  102. }
  103. }
  104. // GetEndTimeNumber 获取这个单元的结束时间,单位是秒
  105. func (s SubUnit) GetEndTimeNumber(realOrOffsetTime bool) float64 {
  106. return my_util.Time2SecendNumber(s.GetEndTime(realOrOffsetTime))
  107. }
  108. // GetEndTime 获取这个单元的起始时间
  109. func (s SubUnit) GetEndTime(realOrOffsetTime bool) time.Time {
  110. if realOrOffsetTime == true {
  111. return s.offsetEndTime.Add(my_util.Time2Duration(s.baseTime))
  112. } else {
  113. return s.offsetEndTime
  114. }
  115. }
  116. // GetTimelineRange 开始到结束的时间长度,单位是秒
  117. func (s SubUnit) GetTimelineRange() float64 {
  118. return s.GetEndTimeNumber(false) - s.GetStartTimeNumber(false)
  119. }
  120. // GetOffsetTimeNumber 偏移时间,单位是秒
  121. func (s SubUnit) GetOffsetTimeNumber() float64 {
  122. return my_util.Time2SecendNumber(s.baseTime)
  123. }
  124. // GetFFMPEGCutRange 这里会生成导出 FFMPEG 的参数字段,起始时间和结束的时间长度
  125. func (s SubUnit) GetFFMPEGCutRange(expandTimeRange float64) (string, string) {
  126. var tmpStartTime time.Time
  127. if s.GetStartTimeNumber(true)-expandTimeRange < 0 {
  128. tmpStartTime = time.Time{}
  129. } else {
  130. startTime := s.GetStartTime(true)
  131. subTime := time.Duration(expandTimeRange) * time.Second
  132. tmpStartTime = startTime.Add(-subTime)
  133. }
  134. return fmt.Sprintf("%d:%d:%d.%d", tmpStartTime.Hour(), tmpStartTime.Minute(), tmpStartTime.Second(), tmpStartTime.Nanosecond()/1000/1000),
  135. fmt.Sprintf("%f", s.GetTimelineRange()+expandTimeRange)
  136. }
  137. // RealTimeToOffsetTime 真实时间转偏移时间
  138. func (s SubUnit) RealTimeToOffsetTime(realTime time.Time) time.Time {
  139. dd := my_util.Time2Duration(s.baseTime)
  140. return realTime.Add(-dd)
  141. }