Browse Source

修复 sub_unit.go 细节

Signed-off-by: allan716 <[email protected]>
allan716 4 years ago
parent
commit
f7eb68c334

+ 7 - 6
internal/pkg/sub_helper/sub_helper.go

@@ -375,7 +375,9 @@ func MergeMultiDialogue4EngSubtitle(inSubParser *subparser.FileInfo) {
 	2. 将整个字幕,抽取连续 5 句对话为一个单元,提取时间片段信息
 */
 func GetVADINfoFromSub(infoSrc *subparser.FileInfo, FrontAndEndPer float64, SubUnitMaxCount int) ([]SubUnit, error) {
-
+	if SubUnitMaxCount < 0 {
+		SubUnitMaxCount = 0
+	}
 	srcSubUnitList := make([]SubUnit, 0)
 	srcOneSubUnit := NewSubUnit()
 	srcTimeFormat := infoSrc.GetTimeFormat()
@@ -387,19 +389,18 @@ func GetVADINfoFromSub(infoSrc *subparser.FileInfo, FrontAndEndPer float64, SubU
 	}
 	srcDuration := my_util.Time2SecendNumber(lastDialogueExTimeEnd)
 
-	for index, oneDialogueEx := range infoSrc.DialoguesEx {
+	for i := 0; i < len(infoSrc.DialoguesEx); i++ {
 
-		oneDialogueExTimeStart, err := time.Parse(srcTimeFormat, oneDialogueEx.StartTime)
+		oneDialogueExTimeStart, err := time.Parse(srcTimeFormat, infoSrc.DialoguesEx[i].StartTime)
 		if err != nil {
 			return nil, err
 		}
-		oneDialogueExTimeEnd, err := time.Parse(srcTimeFormat, oneDialogueEx.EndTime)
+		oneDialogueExTimeEnd, err := time.Parse(srcTimeFormat, infoSrc.DialoguesEx[i].EndTime)
 		if err != nil {
 			return nil, err
 		}
 
 		oneStart := my_util.Time2SecendNumber(oneDialogueExTimeStart)
-		//oneEnd := pkg.Time2SecendNumber(oneDialogueExTimeEnd)
 
 		if FrontAndEndPer > 0 {
 			if srcDuration*FrontAndEndPer > oneStart || srcDuration*(1.0-FrontAndEndPer) < oneStart {
@@ -408,7 +409,7 @@ func GetVADINfoFromSub(infoSrc *subparser.FileInfo, FrontAndEndPer float64, SubU
 		}
 
 		// 如果当前的这一句话,为空,或者进过正则表达式剔除特殊字符后为空,则跳过
-		if my_util.ReplaceSpecString(infoSrc.GetDialogueExContent(index), "") == "" {
+		if my_util.ReplaceSpecString(infoSrc.GetDialogueExContent(i), "") == "" {
 			continue
 		}
 		// 低于 5句对白,则添加

+ 43 - 9
internal/pkg/sub_helper/sub_unit.go

@@ -15,19 +15,29 @@ type SubUnit struct {
 	VADList         []vad.VADInfo
 	subCount        int
 	firstAdd        bool
+	outVADBytes     []byte
 }
 
 func NewSubUnit() *SubUnit {
 	return &SubUnit{
-		VADList:  make([]vad.VADInfo, 0),
-		subCount: 0,
-		firstAdd: false,
+		VADList:     make([]vad.VADInfo, 0),
+		subCount:    0,
+		firstAdd:    false,
+		outVADBytes: make([]byte, 0),
 	}
 }
 
 // AddAndInsert 添加一句对白进来,并且填充中间的空白,间隔 10ms
 func (s *SubUnit) AddAndInsert(oneSubStartTime, oneSubEndTime time.Time) {
 
+	/*
+		这里有个比较有意思的细节,字幕拆分到 dialogue 的时候,可能连续的多个 dialogue 是时间轴连续的
+		但是实际上的语言就是可以分为几个句子的
+		那么,在本函数中,就需要判断插入的时候,与上一句话的时间轴关系,前置无需进行句子的合并
+		如果两句话时间轴是连续的(差值为0),那么就要主动修改这一点,采取的方案可以是
+		1. 前后各 0.001 秒即可
+		2. 后面这一句向后 0.002 秒(暂时优先考虑这个,容易实现)
+	*/
 	const perWindows = float64(vad.FrameDuration) / 1000
 
 	// 不是第一次添加,那么就需要把两句对白中间间隔的 active == false 的插入,插入间隙
@@ -37,7 +47,14 @@ func (s *SubUnit) AddAndInsert(oneSubStartTime, oneSubEndTime time.Time) {
 		nowEndOffsetTime := s.GetEndTimeNumber(false)
 
 		needAddRange := nowStartOffsetTime - nowEndOffsetTime
-		if needAddRange > perWindows {
+
+		if needAddRange == 0 {
+			// 说明是连续的句子,向后加 0.002 秒
+			addMore := time.Duration((s.GetEndTimeNumber(true) + 0.002) * math.Pow10(9))
+			s.VADList = append(s.VADList, *vad.NewVADInfoBase(false, addMore))
+			// 因为是连续的两句话的时间轴,强制插入了一个点,那么就需要在这句话的 Start 部分向后延迟对应的秒数
+			oneSubStartTime = oneSubStartTime.Add(time.Duration(0.002 * math.Pow10(9)))
+		} else {
 			for i := 0.0; i < needAddRange; {
 
 				s.VADList = append(s.VADList, *vad.NewVADInfoBase(false, time.Duration((s.GetEndTimeNumber(true)+i)*math.Pow10(9))))
@@ -62,12 +79,12 @@ func (s *SubUnit) AddAndInsert(oneSubStartTime, oneSubEndTime time.Time) {
 	nowEndOffsetTime := my_util.Time2SecendNumber(nowEndTime)
 
 	needAddRange := nowEndOffsetTime - nowStartOffsetTime
-	if needAddRange > perWindows {
-		for i := 0.0; i < needAddRange; {
-			s.VADList = append(s.VADList, *vad.NewVADInfoBase(true, time.Duration((my_util.Time2SecendNumber(oneSubStartTime)+i)*math.Pow10(9))))
-			i += perWindows
-		}
+
+	for i := 0.0; i < needAddRange; {
+		s.VADList = append(s.VADList, *vad.NewVADInfoBase(true, time.Duration((my_util.Time2SecendNumber(oneSubStartTime)+i)*math.Pow10(9))))
+		i += perWindows
 	}
+
 	s.subCount++
 }
 
@@ -76,6 +93,23 @@ func (s SubUnit) GetDialogueCount() int {
 	return s.subCount
 }
 
+// GetVADSlice 获取 VAD 的 byte 数组信息
+func (s *SubUnit) GetVADSlice() []byte {
+
+	if len(s.outVADBytes) != len(s.VADList) {
+		s.outVADBytes = make([]byte, len(s.VADList))
+		for i := 0; i < len(s.VADList); i++ {
+			if s.VADList[i].Active == true {
+				s.outVADBytes[i] = 1
+			} else {
+				s.outVADBytes[i] = 0
+			}
+		}
+	}
+
+	return s.outVADBytes
+}
+
 // GetStartTimeNumber 获取这个单元的起始时间,单位是秒
 func (s SubUnit) GetStartTimeNumber(realOrOffsetTime bool) float64 {
 	return my_util.Time2SecendNumber(s.GetStartTime(realOrOffsetTime))

+ 14 - 10
internal/pkg/sub_timeline_fixer/fixer.go

@@ -384,7 +384,7 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(infoBase, infoSrc *subparser.FileInfo
 		}
 		// 导出当前的字幕文件适合与匹配的范围的临时字幕文件
 		startTimeString, subLength = srcSubUnit.GetFFMPEGCutRange(0)
-		_, errString, err = s.ffmpegHelper.ExportSubArgsByTimeRange(infoSrc.FileFullPath, "src", startTimeString, subLength)
+		nowTmpSubSrcFPath, errString, err := s.ffmpegHelper.ExportSubArgsByTimeRange(infoSrc.FileFullPath, "src", startTimeString, subLength)
 		if err != nil {
 			log_helper.GetLogger().Errorln("ExportSubArgsByTimeRange src", errString, err)
 			return false, 0, 0, err
@@ -409,6 +409,18 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(infoBase, infoSrc *subparser.FileInfo
 
 		var nowSrcSubTimeLineData = make([]opts.LineData, 0)
 		var nowSrcSubXAxis = make([]string, 0)
+
+		outDir := filepath.Dir(nowTmpSubBaseFPath)
+
+		outBaseName := filepath.Base(nowTmpSubBaseFPath)
+		outSrcName := filepath.Base(nowTmpSubSrcFPath)
+
+		outBaseNameWithOutExt := strings.ReplaceAll(outBaseName, filepath.Ext(outBaseName), "")
+		outSrcNameWithOutExt := strings.ReplaceAll(outSrcName, filepath.Ext(outSrcName), "")
+
+		srcSubVADStaticLineFullPath := filepath.Join(outDir, outSrcNameWithOutExt+"_sub_src.html")
+		baseSubVADStaticLineFullPath := filepath.Join(outDir, outBaseNameWithOutExt+"_sub_base.html")
+
 		// src
 		for _, vadInfo := range srcSubUnit.VADList {
 			nowSrcSubTimeLineData = append(nowSrcSubTimeLineData, opts.LineData{Value: vadInfo.Active})
@@ -419,12 +431,6 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(infoBase, infoSrc *subparser.FileInfo
 			nowSrcSubXAxis = append(nowSrcSubXAxis, fmt.Sprintf("%f", nowOffsetTime))
 		}
 
-		outDir := filepath.Dir(nowTmpSubBaseFPath)
-		outBaseName := filepath.Base(nowTmpSubBaseFPath)
-		outBaseNameWithOutExt := strings.ReplaceAll(outBaseName, filepath.Ext(outBaseName), "")
-
-		srcSubVADStaticLineFullPath := filepath.Join(outDir, outBaseNameWithOutExt+"_sub_src.html")
-
 		err = SaveStaticLineV2("Sub src", srcSubVADStaticLineFullPath, nowSrcSubXAxis, nowSrcSubTimeLineData)
 		if err != nil {
 			return false, 0, 0, err
@@ -439,8 +445,6 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(infoBase, infoSrc *subparser.FileInfo
 			nowBaseSubXAxis = append(nowBaseSubXAxis, fmt.Sprintf("%f", nowVADInfoTimeNumber))
 		}
 
-		baseSubVADStaticLineFullPath := filepath.Join(outDir, outBaseNameWithOutExt+"_sub_base.html")
-
 		err = SaveStaticLineV2("Sub base", baseSubVADStaticLineFullPath, nowBaseSubXAxis, nowBaseSubTimeLineData)
 		if err != nil {
 			return false, 0, 0, err
@@ -564,5 +568,5 @@ func (s *SubTimelineFixer) GetOffsetTimeV3(audioInfo vad.AudioInfo, infoSrc *sub
 
 const FixMask = "-fix"
 const FrontAndEndPer = 0.10 // 前百分之 15 和后百分之 15 都不进行识别
-const SubUnitMaxCount = 50  // 一个 Sub单元有五句对白
+const SubUnitMaxCount = 100 // 一个 Sub单元有五句对白
 const ExpandTimeRange = 50  // 从字幕的时间轴片段需要向前和向后多匹配一部分的音频,这里定义的就是这个 range 以分钟为单位, 正负 60 秒

+ 19 - 13
internal/pkg/sub_timeline_fixer/fixer_test.go

@@ -394,12 +394,12 @@ func TestGetOffsetTimeV2(t *testing.T) {
 		t.Fatal(err)
 	}
 	testRootDirYes := filepath.Join(testRootDir, "yes")
-	//testRootDirNo := filepath.Join(testRootDir, "no")
+	testRootDirNo := filepath.Join(testRootDir, "no")
 	subParserHub := sub_parser_hub.NewSubParserHub(ass.NewParser(), srt.NewParser())
 
 	type args struct {
-		enSubFile              string
-		ch_enSubFile           string
+		baseSubFile            string
+		srcSubFile             string
 		staticLineFileSavePath string
 	}
 	tests := []struct {
@@ -411,15 +411,21 @@ func TestGetOffsetTimeV2(t *testing.T) {
 		/*
 			这里有几个比较理想的字幕时间轴校正的示例
 		*/
-		{name: "R&M S05E01", args: args{enSubFile: filepath.Join(testRootDirYes, "R&M S05E01 - English.srt"),
-			ch_enSubFile:           filepath.Join(testRootDirYes, "R&M S05E01 - 简英.srt"),
+		{name: "R&M S05E01", args: args{baseSubFile: filepath.Join(testRootDirYes, "R&M S05E01 - English.srt"),
+			srcSubFile:             filepath.Join(testRootDirYes, "R&M S05E01 - 简英.srt"),
 			staticLineFileSavePath: "bar.html"}, want: -6.42981818181818, wantErr: false},
-		{name: "R&M S05E10", args: args{enSubFile: filepath.Join(testRootDirYes, "R&M S05E10 - English.ass"),
-			ch_enSubFile:           filepath.Join(testRootDirYes, "R&M S05E10 - 简英.ass"),
+		{name: "R&M S05E10", args: args{baseSubFile: filepath.Join(testRootDirYes, "R&M S05E10 - English.ass"),
+			srcSubFile:             filepath.Join(testRootDirYes, "R&M S05E10 - 简英.ass"),
 			staticLineFileSavePath: "bar.html"}, want: -6.335985401459854, wantErr: false},
-		{name: "基地 S01E03", args: args{enSubFile: filepath.Join(testRootDirYes, "基地 S01E03 - English.ass"),
-			ch_enSubFile:           filepath.Join(testRootDirYes, "基地 S01E03 - 简英.ass"),
+		{name: "基地 S01E03", args: args{baseSubFile: filepath.Join(testRootDirYes, "基地 S01E03 - English.ass"),
+			srcSubFile:             filepath.Join(testRootDirYes, "基地 S01E03 - 简英.ass"),
 			staticLineFileSavePath: "bar.html"}, want: -32.09061538461539, wantErr: false},
+
+		{name: "Don't Breathe 2 (2021) - shooter-srt", args: args{
+			baseSubFile:            filepath.Join(testRootDirNo, "Don't Breathe 2 (2021).chinese(inside).srt"),
+			srcSubFile:             filepath.Join(testRootDirNo, "Don't Breathe 2 (2021).chinese(简英,shooter).srt"),
+			staticLineFileSavePath: "bar.html"},
+			want: 0, wantErr: false},
 	}
 
 	timelineFixer := NewSubTimelineFixer(sub_timeline_fiexer.SubTimelineFixerConfig{
@@ -432,7 +438,7 @@ func TestGetOffsetTimeV2(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 
-			bFind, infoBase, err := subParserHub.DetermineFileTypeFromFile(tt.args.enSubFile)
+			bFind, infoBase, err := subParserHub.DetermineFileTypeFromFile(tt.args.baseSubFile)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -445,7 +451,7 @@ func TestGetOffsetTimeV2(t *testing.T) {
 			*/
 			//sub_helper.MergeMultiDialogue4EngSubtitle(infoBase)
 
-			bFind, infoSrc, err := subParserHub.DetermineFileTypeFromFile(tt.args.ch_enSubFile)
+			bFind, infoSrc, err := subParserHub.DetermineFileTypeFromFile(tt.args.srcSubFile)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -458,7 +464,7 @@ func TestGetOffsetTimeV2(t *testing.T) {
 			*/
 			//sub_helper.MergeMultiDialogue4EngSubtitle(infoSrc)
 
-			bok, got, sd, err := timelineFixer.GetOffsetTimeV2(infoBase, infoSrc, tt.args.ch_enSubFile+"-bar.html", tt.args.ch_enSubFile+".log")
+			bok, got, sd, err := timelineFixer.GetOffsetTimeV2(infoBase, infoSrc, tt.args.srcSubFile+"-bar.html", tt.args.srcSubFile+".log")
 			if (err != nil) != tt.wantErr {
 				t.Errorf("GetOffsetTimeV1() error = %v, wantErr %v", err, tt.wantErr)
 				return
@@ -475,7 +481,7 @@ func TestGetOffsetTimeV2(t *testing.T) {
 			//}
 
 			if bok == true && got != 0 {
-				_, err = timelineFixer.FixSubTimeline(infoSrc, got, tt.args.ch_enSubFile+FixMask+infoBase.Ext)
+				_, err = timelineFixer.FixSubTimeline(infoSrc, got, tt.args.srcSubFile+FixMask+infoBase.Ext)
 				if err != nil {
 					t.Fatal(err)
 				}