소스 검색

尝试修复 fixer.go V2 音频的问题

Signed-off-by: allan716 <[email protected]>
allan716 3 년 전
부모
커밋
46b29173b9

+ 1 - 0
.gitignore

@@ -56,3 +56,4 @@
 /TestData/ffmpeg/test
 /internal/pkg/ffmpeg_helper/config.yaml
 /internal/pkg/ffmpeg_helper/Logs
+/internal/pkg/sub_timeline_fixer/*.html

+ 50 - 0
internal/pkg/debug_view/debug_view.go

@@ -0,0 +1,50 @@
+package debug_view
+
+import (
+	"fmt"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/vad"
+	"github.com/go-echarts/go-echarts/v2/charts"
+	"github.com/go-echarts/go-echarts/v2/opts"
+	"os"
+)
+
+func SaveDebugChart(subUnit sub_helper.SubUnit, title, subTitle string) error {
+
+	return SaveDebugChartBase(subUnit.VADList, title, subTitle)
+}
+
+func SaveDebugChartBase(vadList []vad.VADInfo, title, subTitle string) error {
+
+	line := charts.NewBar()
+	line.SetGlobalOptions(charts.WithTitleOpts(opts.Title{
+		Title:    title,
+		Subtitle: subTitle,
+	}))
+	// 构建 X 轴
+	xAxis := make([]string, len(vadList))
+	for i := 0; i < len(vadList); i++ {
+		xAxis[i] = fmt.Sprintf("%d", i)
+	}
+
+	lineData := make([]opts.BarData, len(vadList))
+	for i := 0; i < len(vadList); i++ {
+		value := -1
+		if vadList[i].Active == true {
+			value = 1
+		}
+		lineData[i] = opts.BarData{Value: value}
+	}
+
+	// Put data into instance
+	line.SetXAxis(xAxis).
+		AddSeries("VAD", lineData)
+	// Where the magic happens
+	f, err := os.Create(title + "bar.html")
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	return line.Render(f)
+}

+ 1 - 1
internal/pkg/emby_api/emby_api_test.go

@@ -43,7 +43,7 @@ func TestEmbyHelper_GetItemVideoInfoByUserId(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	println(videoInfo.Name, videoInfo.Path, "Default Sub Index:", videoInfo.GetDefaultSubIndex())
+	println(videoInfo.Name, videoInfo.Path, "Default Sub OffsetIndex:", videoInfo.GetDefaultSubIndex())
 }
 
 func TestEmbyHelper_UpdateVideoSubList(t *testing.T) {

+ 38 - 11
internal/pkg/my_util/util.go

@@ -448,18 +448,18 @@ func WriteStrings2File(desfilePath string, strings []string) error {
 	return nil
 }
 
-func Time2SecendNumber(inTime time.Time) float64 {
-	outSecend := 0.0
-	outSecend += float64(inTime.Hour() * 60 * 60)
-	outSecend += float64(inTime.Minute() * 60)
-	outSecend += float64(inTime.Second())
-	outSecend += float64(inTime.Nanosecond()) / 1000 / 1000 / 1000
-
-	return outSecend
+func Time2SecondNumber(inTime time.Time) float64 {
+	outSecond := 0.0
+	outSecond += float64(inTime.Hour() * 60 * 60)
+	outSecond += float64(inTime.Minute() * 60)
+	outSecond += float64(inTime.Second())
+	outSecond += float64(inTime.Nanosecond()) / 1000 / 1000 / 1000
+
+	return outSecond
 }
 
 func Time2Duration(inTime time.Time) time.Duration {
-	return time.Duration(Time2SecendNumber(inTime) * math.Pow10(9))
+	return time.Duration(Time2SecondNumber(inTime) * math.Pow10(9))
 }
 
 // ReplaceSpecString 替换特殊的字符
@@ -496,8 +496,19 @@ func MakePowerOfTwo(x int64) int64 {
 	return int64(math.Pow(2, float64(tmpRound)))
 }
 
-// Make10msMultiple 将传入的秒,规整到 10ms 的倍数,返回依然是 秒
-func Make10msMultiple(input float64) float64 {
+// MakeCeil10msMultipleFromFloat 将传入的秒,规整到 10ms 的倍数,返回依然是 秒,向上取整
+func MakeCeil10msMultipleFromFloat(input float64) float64 {
+	const bb = 100
+	// 先转到 10 ms 单位,比如传入是 1.912 - > 191.2
+	t10ms := input * bb
+	// 191.2 - > 192.0
+	newT10ms := math.Ceil(t10ms)
+	// 转换回来
+	return newT10ms / bb
+}
+
+// MakeFloor10msMultipleFromFloat 将传入的秒,规整到 10ms 的倍数,返回依然是 秒,向下取整
+func MakeFloor10msMultipleFromFloat(input float64) float64 {
 	const bb = 100
 	// 先转到 10 ms 单位,比如传入是 1.912 - > 191.2
 	t10ms := input * bb
@@ -506,3 +517,19 @@ func Make10msMultiple(input float64) float64 {
 	// 转换回来
 	return newT10ms / bb
 }
+
+// MakeCeil10msMultipleFromTime 向上取整,规整到 10ms 的倍数
+func MakeCeil10msMultipleFromTime(input time.Time) time.Time {
+
+	nowTime := MakeCeil10msMultipleFromFloat(Time2SecondNumber(input))
+	newTime := time.Time{}.Add(time.Duration(nowTime * math.Pow10(9)))
+	return newTime
+}
+
+// MakeFloor10msMultipleFromTime 向下取整,规整到 10ms 的倍数
+func MakeFloor10msMultipleFromTime(input time.Time) time.Time {
+
+	nowTime := MakeFloor10msMultipleFromFloat(Time2SecondNumber(input))
+	newTime := time.Time{}.Add(time.Duration(nowTime * math.Pow10(9)))
+	return newTime
+}

+ 25 - 13
internal/pkg/sub_helper/sub_helper.go

@@ -398,7 +398,7 @@ func GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(fileInfo *subparser.FileIn
 		return nil, err
 	}
 	// 相当于总时长
-	fullDuration := my_util.Time2SecendNumber(lastDialogueExTimeEnd)
+	fullDuration := my_util.Time2SecondNumber(lastDialogueExTimeEnd)
 	// 最低的起始时间,因为可能需要裁剪范围
 	startRangeTimeMin := fullDuration * SkipFrontAndEndPer
 	endRangeTimeMax := fullDuration * (1.0 - SkipFrontAndEndPer)
@@ -417,7 +417,7 @@ func GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(fileInfo *subparser.FileIn
 			return nil, err
 		}
 
-		oneStart := my_util.Time2SecendNumber(oneDialogueExTimeStart)
+		oneStart := my_util.Time2SecondNumber(oneDialogueExTimeStart)
 		if SkipFrontAndEndPer > 0 {
 			if fullDuration*SkipFrontAndEndPer > oneStart || fullDuration*(1.0-SkipFrontAndEndPer) < oneStart {
 				continue
@@ -487,8 +487,8 @@ func GetVADInfosFromSub(fileInfo *subparser.FileInfo, SkipFrontAndEndPer float64
 		return nil, err
 	}
 	// 字幕的时长,对时间进行向下取整
-	subStartTimeFloor := my_util.Make10msMultiple(my_util.Time2SecendNumber(subStartTime))
-	subEndTimeFloor := my_util.Make10msMultiple(my_util.Time2SecendNumber(subEndTime))
+	subStartTimeFloor := my_util.MakeFloor10msMultipleFromFloat(my_util.Time2SecondNumber(subStartTime))
+	subEndTimeFloor := my_util.MakeFloor10msMultipleFromFloat(my_util.Time2SecondNumber(subEndTime))
 
 	subFullSecondTimeFloor := subEndTimeFloor - subStartTimeFloor
 	// 根据这个时长就能够得到一个完整的 VAD List,然后再通过每一句对白进行 VAD 值的调整即可,这样就能够保证
@@ -504,7 +504,12 @@ func GetVADInfosFromSub(fileInfo *subparser.FileInfo, SkipFrontAndEndPer float64
 	skipStartIndex := int(float64(vadLen) * SkipFrontAndEndPer)
 	skipEndIndex := vadLen - skipStartIndex
 	// 现在需要从 fileInfo 的每一句对白也就对应一段连续的 VAD active = true 来进行改写,记得向下取整
-	for _, dialogueEx := range fileInfo.DialoguesEx {
+	for index, dialogueEx := range fileInfo.DialoguesEx {
+
+		// 如果当前的这一句话,为空,或者进过正则表达式剔除特殊字符后为空,则跳过
+		if my_util.ReplaceSpecString(fileInfo.GetDialogueExContent(index), "") == "" {
+			continue
+		}
 
 		// 字幕的开始时间
 		oneDialogueStartTime, err := fileInfo.ParseTime(dialogueEx.StartTime)
@@ -517,17 +522,21 @@ func GetVADInfosFromSub(fileInfo *subparser.FileInfo, SkipFrontAndEndPer float64
 			return nil, err
 		}
 		// 字幕的时长,对时间进行向下取整
-		oneDialogueStartTimeFloor := my_util.Make10msMultiple(my_util.Time2SecendNumber(oneDialogueStartTime))
-		oneDialogueEndTimeFloor := my_util.Make10msMultiple(my_util.Time2SecendNumber(oneDialogueEndTime))
+		oneDialogueStartTimeFloor := my_util.MakeCeil10msMultipleFromFloat(my_util.Time2SecondNumber(oneDialogueStartTime))
+		oneDialogueEndTimeFloor := my_util.MakeFloor10msMultipleFromFloat(my_util.Time2SecondNumber(oneDialogueEndTime))
 		// 得到一句对白的时长
 		changeVADStartIndex := int(oneDialogueStartTimeFloor * 100)
 		changeVADEndIndex := int(oneDialogueEndTimeFloor * 100)
 		// 跳过整体的前后百分比
-		if changeVADStartIndex < skipStartIndex {
-			changeVADStartIndex = skipStartIndex
+		if changeVADStartIndex < skipStartIndex || changeVADEndIndex > skipEndIndex {
+			continue
 		}
-		if changeVADEndIndex > skipEndIndex {
-			changeVADEndIndex = skipEndIndex
+		// 如果上一个对白的最后一个 OffsetIndex 链接着当前这一句的索引的 VAD 信息 active 是 true 就设置为 false
+		lastDialogueEndIndex := changeVADStartIndex - 1
+		if lastDialogueEndIndex >= 0 {
+			if subVADs[lastDialogueEndIndex].Active == true {
+				subVADs[lastDialogueEndIndex].Active = false
+			}
 		}
 		// 调整之前做好的整体 VAD 的信息,符合 VAD active = true
 		for i := changeVADStartIndex; i < changeVADEndIndex; i++ {
@@ -535,12 +544,15 @@ func GetVADInfosFromSub(fileInfo *subparser.FileInfo, SkipFrontAndEndPer float64
 		}
 	}
 	// 整体的 VAD 信息构建完了,现在需要进行切割,分成多份
-	onePartLen := vadLen / pieces
+	// 需要根据去头去尾,调整整体的总长度再进行多分的拆分
+	afterCutVADLen := vadLen - 2*skipStartIndex
+	onePartLen := afterCutVADLen / pieces
 	// 余下的不要了,暂定
 	//yu := vadLen % pieces
 	for i := 0; i < pieces; i++ {
 		tmpSubUnit := NewSubUnit()
-		tmpVADList := subVADs[i*onePartLen : i*onePartLen+onePartLen]
+		// 截取出来当前这一段
+		tmpVADList := subVADs[skipStartIndex+i*onePartLen : skipStartIndex+i*onePartLen+onePartLen]
 		tmpSubUnit.VADList = tmpVADList
 
 		tmpStartTime := time.Time{}

+ 14 - 54
internal/pkg/sub_helper/sub_helper_test.go

@@ -26,7 +26,7 @@ func TestDeleteOneSeasonSubCacheFolder(t *testing.T) {
 	}
 }
 
-func TestGetVADInfoFeatureFromSub(t *testing.T) {
+func TestGetVADInfosFromSub(t *testing.T) {
 
 	// 这两个字幕是一样的,只不过是格式不同而已
 	subParserHub := sub_parser_hub.NewSubParserHub(ass.NewParser(), srt.NewParser())
@@ -53,69 +53,29 @@ func TestGetVADInfoFeatureFromSub(t *testing.T) {
 			len(infoBase.DialoguesEx), len(infoSrc.DialoguesEx)))
 	}
 
-	baseUnitList, err := GetVADInfoFeatureFromSub(infoBase, FrontAndEndPerBase, 10000, true)
-	if err != nil {
-		t.Fatal(err)
-	}
-	baseUnit := baseUnitList[0]
-	// Src,截取的部分要小于 Base 的部分
-	srcUnitList, err := GetVADInfoFeatureFromSub(infoSrc, FrontAndEndPerBase, 10000, true)
-	if err != nil {
-		t.Fatal(err)
-	}
-	srcUnit := srcUnitList[0]
-
-	if len(baseUnit.VADList) != len(srcUnit.VADList) {
-
-		t.Fatal(fmt.Sprintf("VAD List Base And Src Not Same Length, baseUnit.VADList Len = %v, srcUnit.VADList Len = %v",
-			len(baseUnit.VADList), len(srcUnit.VADList)))
-	}
-
-	//for i := 0; i < len(baseUnit.VADList); i++ {
-	//
-	//}
-
-	println("Done")
-}
-
-const FrontAndEndPerBase = 0
-
-func TestGetVADInfosFromSub(t *testing.T) {
-
-	// 这两个字幕是一样的,只不过是格式不同而已
-	subParserHub := sub_parser_hub.NewSubParserHub(ass.NewParser(), srt.NewParser())
-	baseSubFile := "C:\\Tmp\\Rick and Morty - S05E01\\英_2.srt"
-	srcSubFile := "C:\\Tmp\\Rick and Morty - S05E01\\英_2.ass"
-
-	bFind, infoBase, err := subParserHub.DetermineFileTypeFromFile(baseSubFile)
+	baseSubUnits, err := GetVADInfosFromSub(infoBase, FrontAndEndPerBase, 1)
 	if err != nil {
 		t.Fatal(err)
 	}
-	if bFind == false {
-		t.Fatal("sub not match")
-	}
-	bFind, infoSrc, err := subParserHub.DetermineFileTypeFromFile(srcSubFile)
+	baseSubUnit := baseSubUnits[0]
+	srcSubUnits, err := GetVADInfosFromSub(infoSrc, FrontAndEndPerBase, 1)
 	if err != nil {
 		t.Fatal(err)
 	}
-	if bFind == false {
-		t.Fatal("sub not match")
+	srcSubUnit := srcSubUnits[0]
+	if len(baseSubUnit.VADList) != len(srcSubUnit.VADList) {
+		t.Fatal(fmt.Sprintf("info Base And Src Parse Error, infoBase.VADList Len = %v, infoSrc.VADList Len = %v",
+			len(baseSubUnit.VADList), len(srcSubUnit.VADList)))
 	}
 
-	if len(infoBase.DialoguesEx) != len(infoSrc.DialoguesEx) {
-		t.Fatal(fmt.Sprintf("info Base And Src Parse Error, infoBase.DialoguesEx Len = %v, infoSrc.DialoguesEx Len = %v",
-			len(infoBase.DialoguesEx), len(infoSrc.DialoguesEx)))
-	}
-
-	baseSubUnits, err := GetVADInfosFromSub(infoBase, 0, 1)
-	if err != nil {
-		t.Fatal(err)
-	}
-	srcSubUnits, err := GetVADInfosFromSub(infoSrc, 0, 1)
-	if err != nil {
-		t.Fatal(err)
+	for i := 0; i < len(baseSubUnit.VADList); i++ {
+		if baseSubUnit.VADList[i] != srcSubUnit.VADList[i] {
+			println(fmt.Sprintf("base src VADList i=%v, not the same", i))
+		}
 	}
 
 	println(len(baseSubUnits))
 	println(len(srcSubUnits))
 }
+
+const FrontAndEndPerBase = 0

+ 24 - 65
internal/pkg/sub_helper/sub_unit.go

@@ -3,7 +3,6 @@ package sub_helper
 import (
 	"bufio"
 	"fmt"
-	"github.com/allanpk716/ChineseSubFinder/internal/pkg/frechet"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/vad"
 	"math"
@@ -34,6 +33,9 @@ func NewSubUnit() *SubUnit {
 
 func (s *SubUnit) Add(oneSubStartTime, oneSubEndTime time.Time) {
 
+	//oneSubStartTime = my_util.MakeFloor10msMultipleFromTime(oneSubStartTime)
+	//oneSubEndTime = my_util.MakeFloor10msMultipleFromTime(oneSubEndTime)
+
 	if s.firstAdd == false {
 		// 第一次 Add 需要给 baseTime 赋值
 		s.baseTime = oneSubStartTime
@@ -44,9 +46,9 @@ func (s *SubUnit) Add(oneSubStartTime, oneSubEndTime time.Time) {
 	s.offsetEndTime = oneSubEndTime.Add(-my_util.Time2Duration(s.baseTime))
 
 	// 添加 Start
-	s.VADList = append(s.VADList, *vad.NewVADInfoBase(true, time.Duration((my_util.Time2SecendNumber(oneSubStartTime))*math.Pow10(9))))
+	s.VADList = append(s.VADList, *vad.NewVADInfoBase(true, time.Duration((my_util.Time2SecondNumber(oneSubStartTime))*math.Pow10(9))))
 	// 添加 End
-	s.VADList = append(s.VADList, *vad.NewVADInfoBase(false, time.Duration((my_util.Time2SecendNumber(oneSubEndTime))*math.Pow10(9))))
+	s.VADList = append(s.VADList, *vad.NewVADInfoBase(false, time.Duration((my_util.Time2SecondNumber(oneSubEndTime))*math.Pow10(9))))
 
 	s.subCount++
 }
@@ -63,10 +65,13 @@ func (s *SubUnit) AddAndInsert(oneSubStartTime, oneSubEndTime time.Time) {
 		2. 后面这一句向后 0.002 秒(暂时优先考虑这个,容易实现)
 	*/
 
+	//oneSubStartTime = my_util.MakeFloor10msMultipleFromTime(oneSubStartTime)
+	//oneSubEndTime = my_util.MakeFloor10msMultipleFromTime(oneSubEndTime)
+
 	// 不是第一次添加,那么就需要把两句对白中间间隔的 active == false 的插入,插入间隙
 	if len(s.VADList) > 0 {
 		nowStartTime := s.RealTimeToOffsetTime(oneSubStartTime)
-		nowStartOffsetTime := my_util.Time2SecendNumber(nowStartTime)
+		nowStartOffsetTime := my_util.Time2SecondNumber(nowStartTime)
 		nowEndOffsetTime := s.GetEndTimeNumber(false)
 
 		needAddRange := nowStartOffsetTime - nowEndOffsetTime
@@ -98,13 +103,13 @@ func (s *SubUnit) AddAndInsert(oneSubStartTime, oneSubEndTime time.Time) {
 	nowStartTime := s.RealTimeToOffsetTime(oneSubStartTime)
 	nowEndTime := s.RealTimeToOffsetTime(oneSubEndTime)
 
-	nowStartOffsetTime := my_util.Time2SecendNumber(nowStartTime)
-	nowEndOffsetTime := my_util.Time2SecendNumber(nowEndTime)
+	nowStartOffsetTime := my_util.Time2SecondNumber(nowStartTime)
+	nowEndOffsetTime := my_util.Time2SecondNumber(nowEndTime)
 
 	needAddRange := nowEndOffsetTime - nowStartOffsetTime
 
 	for i := 0.0; i < needAddRange; {
-		s.VADList = append(s.VADList, *vad.NewVADInfoBase(true, time.Duration((my_util.Time2SecendNumber(oneSubStartTime)+i)*math.Pow10(9))))
+		s.VADList = append(s.VADList, *vad.NewVADInfoBase(true, time.Duration((my_util.Time2SecondNumber(oneSubStartTime)+i)*math.Pow10(9))))
 		i += perWindows
 	}
 
@@ -170,7 +175,7 @@ func (s *SubUnit) GetVADFloatSlice() []float64 {
 
 // GetStartTimeNumber 获取这个单元的起始时间,单位是秒
 func (s SubUnit) GetStartTimeNumber(realOrOffsetTime bool) float64 {
-	return my_util.Time2SecendNumber(s.GetStartTime(realOrOffsetTime))
+	return my_util.Time2SecondNumber(s.GetStartTime(realOrOffsetTime))
 }
 
 // GetStartTime 获取这个单元的起始时间
@@ -185,7 +190,7 @@ func (s SubUnit) GetStartTime(realOrOffsetTime bool) time.Time {
 // GetEndTimeNumber 获取这个单元的结束时间,单位是秒
 func (s SubUnit) GetEndTimeNumber(realOrOffsetTime bool) float64 {
 
-	return my_util.Time2SecendNumber(s.GetEndTime(realOrOffsetTime))
+	return my_util.Time2SecondNumber(s.GetEndTime(realOrOffsetTime))
 }
 
 // GetEndTime 获取这个单元的起始时间
@@ -197,7 +202,7 @@ func (s SubUnit) GetEndTime(realOrOffsetTime bool) time.Time {
 	}
 }
 
-// GetIndexTime 当前 Index 的时间
+// GetIndexTime 当前 OffsetIndex 的时间
 func (s SubUnit) GetIndexTime(index int, realOrOffsetTime bool) (bool, time.Time) {
 
 	if index >= len(s.VADList) {
@@ -211,7 +216,7 @@ func (s SubUnit) GetIndexTime(index int, realOrOffsetTime bool) (bool, time.Time
 	}
 }
 
-// GetIndexTimeNumber 当前 Index 的时间
+// GetIndexTimeNumber 当前 OffsetIndex 的时间
 func (s SubUnit) GetIndexTimeNumber(index int, realOrOffsetTime bool) (bool, float64) {
 
 	bok, outTime := s.GetIndexTime(index, realOrOffsetTime)
@@ -219,7 +224,7 @@ func (s SubUnit) GetIndexTimeNumber(index int, realOrOffsetTime bool) (bool, flo
 		return false, 0
 	}
 
-	return true, my_util.Time2SecendNumber(outTime)
+	return true, my_util.Time2SecondNumber(outTime)
 }
 
 // GetTimelineRange 开始到结束的时间长度,单位是秒
@@ -229,7 +234,7 @@ func (s SubUnit) GetTimelineRange() float64 {
 
 // GetOffsetTimeNumber 偏移时间,单位是秒
 func (s SubUnit) GetOffsetTimeNumber() float64 {
-	return my_util.Time2SecendNumber(s.baseTime)
+	return my_util.Time2SecondNumber(s.baseTime)
 }
 
 // GetFFMPEGCutRangeString 这里会生成导出 FFMPEG 的参数字段,起始时间和结束的时间长度
@@ -259,7 +264,7 @@ func (s SubUnit) GetExpandRangeIndex(expandTimeRange float64) (int, int) {
 
 	var tmpStartTimeIndex int
 	var tmpEndTimeIndex int
-	// 起始时间 -> Index
+	// 起始时间 -> OffsetIndex
 	if s.GetStartTimeNumber(true)-expandTimeRange < 0 {
 		// 向左偏移的时候是可知有多少可以移动的,越界就置为 0
 		tmpStartTimeIndex = 0
@@ -268,16 +273,16 @@ func (s SubUnit) GetExpandRangeIndex(expandTimeRange float64) (int, int) {
 		startTime := s.GetStartTime(true)
 		subTime := time.Duration(expandTimeRange) * time.Second
 		tmpStartTime := startTime.Add(-subTime)
-		// 需要从秒换算到偏移的 Index 数值,一共多少份
-		tmpStartTimeIndex = int(my_util.Time2SecendNumber(tmpStartTime) / perWindows)
+		// 需要从秒换算到偏移的 OffsetIndex 数值,一共多少份
+		tmpStartTimeIndex = int(my_util.Time2SecondNumber(tmpStartTime) / perWindows)
 	}
-	// 结束时间 -> Index
+	// 结束时间 -> OffsetIndex
 	// 向右移动的时候,总长度是未知的,所以返回的值需要在外部重新 Check 是否会越界
 	endTime := s.GetEndTime(true)
 	subTime := time.Duration(expandTimeRange) * time.Second
 	tmpEndTime := endTime.Add(subTime)
-	// 需要从秒换算到偏移的 Index 数值,一共多少份
-	tmpEndTimeIndex = int(my_util.Time2SecendNumber(tmpEndTime) / perWindows)
+	// 需要从秒换算到偏移的 OffsetIndex 数值,一共多少份
+	tmpEndTimeIndex = int(my_util.Time2SecondNumber(tmpEndTime) / perWindows)
 
 	return tmpStartTimeIndex, tmpEndTimeIndex
 }
@@ -323,52 +328,6 @@ func (s SubUnit) Save2Txt(outFileFPath string, oneLine bool) error {
 	return nil
 }
 
-// GetStartVADList 获取起始时间的 VAD List
-func (s SubUnit) GetStartVADList() []vad.VADInfo {
-
-	outVADList := make([]vad.VADInfo, len(s.VADList))
-	for _, value := range s.VADList {
-		outVADList = append(outVADList, value)
-	}
-	return outVADList
-}
-
-// GetFrechetPoint 获取 Frechet 曲线相似度的数据结构 List,whichOne = 0 所有,whichOne = 1 只有 Start 的点
-func (s SubUnit) GetFrechetPoint(whichOne int) []frechet.Point {
-
-	outPoint := make([]frechet.Point, 0)
-	if whichOne == 0 {
-		// 所有点
-		for _, info := range s.VADList {
-			nowX := 0.0
-			if info.Active == true {
-				nowX = 1.0
-			}
-			nowY := info.Time.Seconds()
-			outPoint = append(outPoint, frechet.Point{
-				X: nowX,
-				Y: nowY,
-			})
-		}
-		return outPoint
-
-	} else {
-		// 只有 Start 点
-		for _, info := range s.GetStartVADList() {
-			nowX := 0.0
-			if info.Active == true {
-				nowX = 1.0
-			}
-			nowY := info.Time.Seconds()
-			outPoint = append(outPoint, frechet.Point{
-				X: nowX,
-				Y: nowY,
-			})
-		}
-		return outPoint
-	}
-}
-
 const perWindows = float64(vad.FrameDuration) / 1000
 
 const addMoreTime = 0.002

+ 21 - 17
internal/pkg/sub_timeline_fixer/fixer.go

@@ -395,9 +395,12 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit
 	audioFloatList := vad.GetFloatSlice(audioVadList)
 
 	srcVADLen := len(srcUnit.VADList)
+	// 滑动窗口的长度
 	srcWindowLen := int(float64(srcVADLen) * MatchPer)
 	srcSlideLen := srcVADLen - srcWindowLen
+	// 窗口可以滑动的长度
 	srcSlideLenHalf := srcSlideLen / 2
+	//
 	oneStep := srcSlideLenHalf / CompareParts
 	if srcSlideLen <= 0 {
 		srcSlideLen = 1
@@ -407,6 +410,7 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit
 	}
 	insertIndex := 0
 	// -------------------------------------------------
+	// 实际 FFT 的匹配逻辑函数
 	fixFunc := func(i interface{}) error {
 		inData := i.(InputData)
 		// -------------------------------------------------
@@ -422,15 +426,17 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit
 			// 使用 音频 来进行匹配
 			// 去掉头和尾,具体百分之多少,见 FrontAndEndPerBase
 			audioCutLen := int(float64(len(inData.AudioVADList)) * FrontAndEndPerBase)
-			offsetIndex, score = fffAligner.Fit(inData.AudioVADList[audioCutLen:len(inData.AudioVADList)-audioCutLen], inData.SrcUnit.GetVADFloatSlice()[inData.Index:srcWindowLen+inData.Index])
+
+			offsetIndex, score = fffAligner.Fit(inData.AudioVADList[audioCutLen:len(inData.AudioVADList)-audioCutLen], inData.SrcUnit.GetVADFloatSlice()[inData.OffsetIndex:srcWindowLen+inData.OffsetIndex])
 			if offsetIndex < 0 {
 				return nil
 			}
-			// offsetIndex 这里得到的是 10ms 为一个单位的 Index,把去掉的头部时间偏移加回来
+			// offsetIndex 这里得到的是 10ms 为一个单位的 OffsetIndex,把去掉的头部时间偏移加回来,以及第一句话的偏移
 			nowBaseStartTime = vad.GetAudioIndex2Time(offsetIndex + audioCutLen)
+			nowBaseStartTime = nowBaseStartTime + inData.SrcUnit.GetStartTimeNumber(true)
 		} else {
 			// 使用 字幕 来进行匹配
-			offsetIndex, score = fffAligner.Fit(inData.BaseUnit.GetVADFloatSlice(), inData.SrcUnit.GetVADFloatSlice()[inData.Index:srcWindowLen+inData.Index])
+			offsetIndex, score = fffAligner.Fit(inData.BaseUnit.GetVADFloatSlice(), inData.SrcUnit.GetVADFloatSlice()[inData.OffsetIndex:inData.OffsetIndex+srcWindowLen])
 			if offsetIndex < 0 {
 				return nil
 			}
@@ -440,7 +446,7 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit
 			}
 		}
 		// 需要校正的字幕
-		bok, nowSrcStartTime := inData.SrcUnit.GetIndexTimeNumber(inData.Index, true)
+		bok, nowSrcStartTime := inData.SrcUnit.GetIndexTimeNumber(inData.OffsetIndex, true)
 		if bok == false {
 			return nil
 		}
@@ -503,10 +509,10 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit
 
 		if bUseSubOrAudioAsBase == true {
 			// 使用字幕
-			err = antPool.Invoke(InputData{BaseUnit: *baseUnit, SrcUnit: *srcUnit, Index: i, Wg: &wg})
+			err = antPool.Invoke(InputData{BaseUnit: *baseUnit, SrcUnit: *srcUnit, OffsetIndex: i, Wg: &wg})
 		} else {
 			// 使用音频
-			err = antPool.Invoke(InputData{AudioVADList: audioFloatList, SrcUnit: *srcUnit, Index: i, Wg: &wg})
+			err = antPool.Invoke(InputData{AudioVADList: audioFloatList, SrcUnit: *srcUnit, OffsetIndex: i, Wg: &wg})
 		}
 
 		if err != nil {
@@ -596,27 +602,25 @@ func (s *SubTimelineFixer) calcMeanAndSD(startDiffTimeList stat.Float64Slice, tm
 
 const FixMask = "-fix"
 const SubOneUnitProcessTimeOut = 60 * 5 * time.Second // 字幕时间轴校正一个单元的超时时间
-const bInsert = true                                  // 是否插入点
-const FrontAndEndPerBase = 0.20                       // 前百分之 15 和后百分之 15 都不进行识别
-const FrontAndEndPerSrc = 0.15                        // 前百分之 20 和后百分之 20 都不进行识别
-const MatchPer = 0.7
+const FrontAndEndPerBase = 0.0                        // 前百分之 15 和后百分之 15 都不进行识别
+const FrontAndEndPerSrc = 0.0                         // 前百分之 20 和后百分之 20 都不进行识别
+const MatchPer = 0.8
 const CompareParts = 5
-
 const FixThreads = 1 // 字幕校正的并发线程
 
 var mutexFixV2 sync.Mutex
 
 type OutputData struct {
 	TimeDiffStartCorrelation float64 // 计算出来的时间轴偏移时间
-	OffsetIndex              float64 // 在这个匹配的 Window 中的 Index
+	OffsetIndex              float64 // 在这个匹配的 Window 中的 OffsetIndex
 	Score                    float64 // 匹配的分数
 	InsertIndex              int     // 第几个 Step
 }
 
 type InputData struct {
-	BaseUnit     sub_helper.SubUnit
-	AudioVADList []float64
-	SrcUnit      sub_helper.SubUnit
-	Index        int
-	Wg           *sync.WaitGroup
+	BaseUnit     sub_helper.SubUnit // 基准 VAD
+	AudioVADList []float64          // 基准 VAD
+	SrcUnit      sub_helper.SubUnit // 需要匹配的 VAD
+	OffsetIndex  int                // 滑动窗体的移动偏移索引
+	Wg           *sync.WaitGroup    // 并发锁
 }

+ 44 - 11
internal/pkg/sub_timeline_fixer/fixer_test.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/ass"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/srt"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/debug_view"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/ffmpeg_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
@@ -440,12 +441,12 @@ func TestGetOffsetTimeV2_BaseSub(t *testing.T) {
 		{name: "R&M S05E01-2", args: args{
 			baseSubFile:            "C:\\Tmp\\Rick and Morty - S05E01\\英_2.ass",
 			srcSubFile:             "C:\\Tmp\\Rick and Morty - S05E01\\英_2.srt",
-			staticLineFileSavePath: "bar.html"}, want: -6.12981818181818, wantErr: false},
+			staticLineFileSavePath: "bar.html"}, want: 0, wantErr: false},
 
 		{name: "R&M S05E01-2", args: args{
 			baseSubFile:            "C:\\Tmp\\Rick and Morty - S05E10\\英_2.srt",
 			srcSubFile:             "C:\\Tmp\\Rick and Morty - S05E10\\英_2.ass",
-			staticLineFileSavePath: "bar.html"}, want: -6.12981818181818, wantErr: false},
+			staticLineFileSavePath: "bar.html"}, want: 0, wantErr: false},
 		/*
 			基地
 		*/
@@ -619,20 +620,39 @@ func TestGetOffsetTimeV2_BaseSub(t *testing.T) {
 				internal/pkg/sub_helper/sub_helper.go 中 MergeMultiDialogue4EngSubtitle 的实现
 			*/
 			//sub_helper.MergeMultiDialogue4EngSubtitle(infoSrc)
-
+			// ---------------------------------------------------------------------------------------
 			// Base,截取的部分要大于 Src 的部分
-			baseUnitList, err := sub_helper.GetVADInfoFeatureFromSub(infoBase, FrontAndEndPerBase, 10000, bInsert)
+			//baseUnitList, err := sub_helper.GetVADInfosFromSub(infoBase, FrontAndEndPerBase, 1)
+			//if err != nil {
+			//	t.Fatal(err)
+			//}
+			//baseUnit := baseUnitList[0]
+
+			baseUnitList2, err := sub_helper.GetVADInfoFeatureFromSub(infoBase, FrontAndEndPerBase, 100000, true)
 			if err != nil {
 				t.Fatal(err)
 			}
-			baseUnit := baseUnitList[0]
+			baseUnit := baseUnitList2[0]
+			debug_view.SaveDebugChart(baseUnit, "baseUnit", "baseUnit")
+			//debug_view.SaveDebugChart(baseUnit2, "baseUnit2", "baseUnit2")
+			//baseUnit = baseUnitList2[0]
+			// ---------------------------------------------------------------------------------------
 			// Src,截取的部分要小于 Base 的部分
-			srcUnitList, err := sub_helper.GetVADInfoFeatureFromSub(infoSrc, FrontAndEndPerSrc, 10000, bInsert)
+			//srcUnitList, err := sub_helper.GetVADInfosFromSub(infoSrc, FrontAndEndPerSrc, 1)
+			//if err != nil {
+			//	t.Fatal(err)
+			//}
+			//srcUnit := srcUnitList[0]
+
+			srcUnitList2, err := sub_helper.GetVADInfoFeatureFromSub(infoSrc, FrontAndEndPerSrc, 100000, true)
 			if err != nil {
 				t.Fatal(err)
 			}
-			srcUnit := srcUnitList[0]
-
+			srcUnit := srcUnitList2[0]
+			debug_view.SaveDebugChart(srcUnit, "srcUnit", "srcUnit")
+			//debug_view.SaveDebugChart(srcUnit2, "srcUnit2", "srcUnit2")
+			//srcUnit = srcUnitList2[0]
+			// ---------------------------------------------------------------------------------------
 			bok, got, sd, err := timelineFixer.GetOffsetTimeV2(&baseUnit, &srcUnit, nil, 0)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("GetOffsetTimeV1() error = %v, wantErr %v", err, tt.wantErr)
@@ -684,6 +704,7 @@ func TestGetOffsetTimeV2_BaseAudio(t *testing.T) {
 			args: args{audioInfo: vad.AudioInfo{
 				FileFullPath: "C:\\Tmp\\Rick and Morty - S05E10\\英_1.pcm"},
 				subFilePath: "C:\\Tmp\\Rick and Morty - S05E10\\英_2.ass"},
+			want: false, want1: 0,
 		},
 		{name: "Rick and Morty - S05E10 -- 1",
 			args: args{audioInfo: vad.AudioInfo{
@@ -695,13 +716,13 @@ func TestGetOffsetTimeV2_BaseAudio(t *testing.T) {
 			args: args{audioInfo: vad.AudioInfo{
 				FileFullPath: "C:\\Tmp\\Rick and Morty - S05E01\\未知语言_1.pcm"},
 				subFilePath: "C:\\Tmp\\Rick and Morty - S05E01\\英_2.ass"},
-			want: true, want1: -6.4,
+			want: false, want1: 0,
 		},
 		{name: "Rick and Morty - S05E01 -- 0",
 			args: args{audioInfo: vad.AudioInfo{
 				FileFullPath: "C:\\Tmp\\Rick and Morty - S05E01\\未知语言_1.pcm"},
 				subFilePath: "C:\\Tmp\\Rick and Morty - S05E01\\英_2.srt"},
-			want: true, want1: -6.4,
+			want: false, want1: 0,
 		},
 		{name: "Rick and Morty - S05E01 -- 1",
 			args: args{audioInfo: vad.AudioInfo{
@@ -729,12 +750,18 @@ func TestGetOffsetTimeV2_BaseAudio(t *testing.T) {
 			*/
 			//sub_helper.MergeMultiDialogue4EngSubtitle(infoSrc)
 			// Src,截取的部分要小于 Base 的部分
-			srcUnitList, err := sub_helper.GetVADInfoFeatureFromSub(infoSrc, FrontAndEndPerSrc, 10000, bInsert)
+			srcUnitList, err := sub_helper.GetVADInfosFromSub(infoSrc, FrontAndEndPerSrc, 1)
 			if err != nil {
 				t.Fatal(err)
 			}
 			srcUnit := srcUnitList[0]
 
+			srcUnitList2, err := sub_helper.GetVADInfoFeatureFromSub(infoSrc, FrontAndEndPerSrc, 10000, true)
+			if err != nil {
+				t.Fatal(err)
+			}
+			srcUnit2 := srcUnitList2[0]
+
 			audioVADInfos, err := vad.GetVADInfoFromAudio(vad.AudioInfo{
 				FileFullPath: tt.args.audioInfo.FileFullPath,
 				SampleRate:   16000,
@@ -751,10 +778,16 @@ func TestGetOffsetTimeV2_BaseAudio(t *testing.T) {
 			}
 
 			got, got1, got2, err := s.GetOffsetTimeV2(nil, &srcUnit, audioVADInfos, duration)
+			got, got1, got2, err = s.GetOffsetTimeV2(nil, &srcUnit2, audioVADInfos, duration)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("GetOffsetTimeV3() error = %v, wantErr %v", err, tt.wantErr)
 				return
 			}
+
+			debug_view.SaveDebugChartBase(audioVADInfos, "audioVADInfos", "audioVADInfos")
+			debug_view.SaveDebugChart(srcUnit, "srcUnit", "srcUnit")
+			debug_view.SaveDebugChart(srcUnit2, "srcUnit2", "srcUnit2")
+
 			if got != tt.want {
 				t.Errorf("GetOffsetTimeV3() got = %v, want %v", got, tt.want)
 			}

+ 5 - 5
internal/pkg/sub_timeline_fixer/sub_compare.go

@@ -23,10 +23,10 @@ func NewSubCompare(maxCompareDialogue int) *SubCompare {
 	return &sc
 }
 
-// Add 添加元素进来比较,这里有个细节,如果理论上需要判断是 Index 是 1-5 ,那么如果 1 add了,2 add 失败的时候,是应该清理后再 add 2
+// Add 添加元素进来比较,这里有个细节,如果理论上需要判断是 OffsetIndex 是 1-5 ,那么如果 1 add了,2 add 失败的时候,是应该清理后再 add 2
 // 还有一种情况,从 1-5,添加到 4 的时候false了,那么应该回退到 2 进行 add,而不是从 4 开始
 func (s *SubCompare) Add(baseNowIndex, srcNowIndex int) bool {
-	// 如果是第一次 Add 的话,就直接把后续需要匹配的 Index 字典的 Key 信息建立好
+	// 如果是第一次 Add 的话,就直接把后续需要匹配的 OffsetIndex 字典的 Key 信息建立好
 	// 再次调用本方法的时候就是 check 是否需要加的 key 存在于 字典 Key 中即可
 	if len(s.baseIndexDict) == 0 {
 		// 第一次
@@ -40,11 +40,11 @@ func (s *SubCompare) Add(baseNowIndex, srcNowIndex int) bool {
 		s.srcNowIndex = srcNowIndex
 	}
 	// 可以理解为第二次开始才进入这个逻辑
-	// 判断是否是预计的顺序 Index
+	// 判断是否是预计的顺序 OffsetIndex
 	_, okBase := s.baseIndexDict[baseNowIndex]
 	_, okSrc := s.srcIndexDict[srcNowIndex]
 	if okBase == false || okSrc == false {
-		// 一定要存在,因为必须是可期待的 Index
+		// 一定要存在,因为必须是可期待的 OffsetIndex
 		return false
 	}
 	// 上面的判断仅仅是确定这个 index 是期望的范围内的,而不能保证顺序
@@ -60,7 +60,7 @@ func (s *SubCompare) Add(baseNowIndex, srcNowIndex int) bool {
 }
 
 // Check 是否 Add 的元素已经足够满足 maxCompareDialogue 的数量要求了
-// 这里有个细节,如果理论上需要判断是 Index 是 1-5 ,如果 add 5 check 的时候 false,那么应该清理后,回退到 2 进行 add,而不是 6 开始
+// 这里有个细节,如果理论上需要判断是 OffsetIndex 是 1-5 ,如果 add 5 check 的时候 false,那么应该清理后,回退到 2 进行 add,而不是 6 开始
 func (s *SubCompare) Check() bool {
 	if len(s.baseIndexList) == 0 && len(s.srcIndexList) == 0 {
 		return true

+ 8 - 1
internal/pkg/vad/vad_helper.go

@@ -103,7 +103,14 @@ func GetFloatSlice(inVADs []VADInfo) []float64 {
 	return outVADFloats
 }
 
-// GetAudioIndex2Time 从 Audio 的 Index 推算出它所在的时间,返回 float64 的秒
+// GetAudioIndex2Time 从 Audio 的 OffsetIndex 推算出它所在的时间,返回 float64 的秒
 func GetAudioIndex2Time(index int) float64 {
 	return float64(index*FrameDuration) / 1000.0
 }
+
+const (
+	// Mode vad mode,VAD 的模式 0-3
+	Mode = 2
+	// FrameDuration frame duration,分析的时间窗口
+	FrameDuration = 10
+)

+ 0 - 7
internal/pkg/vad/vad_info.go

@@ -26,10 +26,3 @@ func NewVADInfoBase(active bool, nowTime time.Duration) *VADInfo {
 		Time:   nowTime,
 	}
 }
-
-const (
-	// Mode vad mode,VAD 的模式 0-3
-	Mode = 3
-	// FrameDuration frame duration,分析的时间窗口
-	FrameDuration = 10
-)

+ 2 - 2
internal/types/emby/type.go

@@ -78,7 +78,7 @@ type EmbyVideoInfo struct {
 			Profile                string  `json:"Profile,omitempty"`
 			Type                   string  `json:"Type"`
 			AspectRatio            string  `json:"AspectRatio,omitempty"`
-			Index                  int     `json:"Index"`
+			Index                  int     `json:"OffsetIndex"`
 			IsExternal             bool    `json:"IsExternal"`
 			IsTextSubtitleStream   bool    `json:"IsTextSubtitleStream"`
 			SupportsExternalStream bool    `json:"SupportsExternalStream"`
@@ -106,7 +106,7 @@ type EmbyVideoInfo struct {
 		Codec                  string `json:"Codec"`
 		Language               string `json:"Language"`
 		DisplayTitle           string `json:"DisplayTitle"`
-		Index                  int    `json:"Index"`
+		Index                  int    `json:"OffsetIndex"`
 		IsExternal             bool   `json:"IsExternal"`
 		IsTextSubtitleStream   bool   `json:"IsTextSubtitleStream"`
 		SupportsExternalStream bool   `json:"SupportsExternalStream"`