diff --git a/.editorconfig b/.editorconfig index d1193ae..cb0017e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -127,6 +127,8 @@ csharp_style_var_elsewhere = true:suggestion csharp_style_var_for_built_in_types = true:suggestion #prefer var when the type is already mentioned on the right-hand side of a declaration expression csharp_style_var_when_type_is_apparent = true:suggestion +# IDE0090: Use 'new(...)' +csharp_style_implicit_object_creation_when_type_is_apparent = false:suggestion #Style - language keyword and framework type options diff --git a/BililiveRecorder.Flv/Pipeline/Rules/HandleDelayedAudioHeaderRule.cs b/BililiveRecorder.Flv/Pipeline/Rules/HandleDelayedAudioHeaderRule.cs index 6a32588..80844ef 100644 --- a/BililiveRecorder.Flv/Pipeline/Rules/HandleDelayedAudioHeaderRule.cs +++ b/BililiveRecorder.Flv/Pipeline/Rules/HandleDelayedAudioHeaderRule.cs @@ -7,11 +7,8 @@ using StructLinq; namespace BililiveRecorder.Flv.Pipeline.Rules { /// - /// 处理延后收到的音频头 + /// 处理延后收到的音频头,移动到音视频数据的前面。 /// - /// - /// 本规则应该放在所有规则前面 - /// public class HandleDelayedAudioHeaderRule : ISimpleProcessingRule { private static readonly ProcessingComment comment1 = new ProcessingComment(CommentType.Unrepairable, "音频数据出现在音频头之前"); diff --git a/BililiveRecorder.Flv/Pipeline/Rules/HandleEndTagRule.cs b/BililiveRecorder.Flv/Pipeline/Rules/HandleEndTagRule.cs index 66e1d85..81ce55f 100644 --- a/BililiveRecorder.Flv/Pipeline/Rules/HandleEndTagRule.cs +++ b/BililiveRecorder.Flv/Pipeline/Rules/HandleEndTagRule.cs @@ -5,7 +5,7 @@ using BililiveRecorder.Flv.Pipeline.Actions; namespace BililiveRecorder.Flv.Pipeline.Rules { /// - /// 处理 end tag + /// 处理 End Tag,遇到的时候对文件进行分段 /// public class HandleEndTagRule : ISimpleProcessingRule { diff --git a/BililiveRecorder.Flv/Pipeline/Rules/HandleNewHeaderRule.cs b/BililiveRecorder.Flv/Pipeline/Rules/HandleNewHeaderRule.cs index a59d14e..2d3575d 100644 --- a/BililiveRecorder.Flv/Pipeline/Rules/HandleNewHeaderRule.cs +++ b/BililiveRecorder.Flv/Pipeline/Rules/HandleNewHeaderRule.cs @@ -8,14 +8,8 @@ using StructLinq.Where; namespace BililiveRecorder.Flv.Pipeline.Rules { /// - /// 处理收到音视频 Header 的情况 + /// 处理音视频 Header。收到音视频 Header 时检查与上一组是否相同,并根据情况删除重复的 Header 或新建文件。
///
- /// - /// 当收到音视频 Header 时检查与上一组是否相同
- /// 并根据情况删除重复的 Header 或新建文件写入
- ///
- /// 本规则为一般规则 - ///
public class HandleNewHeaderRule : ISimpleProcessingRule { private const string VIDEO_HEADER_KEY = "HandleNewHeaderRule_VideoHeader"; diff --git a/BililiveRecorder.Flv/Pipeline/Rules/HandleNewScriptRule.cs b/BililiveRecorder.Flv/Pipeline/Rules/HandleNewScriptRule.cs index 819e2f7..4691a6d 100644 --- a/BililiveRecorder.Flv/Pipeline/Rules/HandleNewScriptRule.cs +++ b/BililiveRecorder.Flv/Pipeline/Rules/HandleNewScriptRule.cs @@ -6,11 +6,8 @@ using BililiveRecorder.Flv.Pipeline.Actions; namespace BililiveRecorder.Flv.Pipeline.Rules { /// - /// 处理收到 Script Tag 的情况 + /// 处理 Script Tag /// - /// - /// 本规则为一般规则 - /// public class HandleNewScriptRule : ISimpleProcessingRule { private const string onMetaData = "onMetaData"; diff --git a/BililiveRecorder.Flv/Pipeline/Rules/RemoveDuplicatedChunkRule.cs b/BililiveRecorder.Flv/Pipeline/Rules/RemoveDuplicatedChunkRule.cs index 8c357a5..476b553 100644 --- a/BililiveRecorder.Flv/Pipeline/Rules/RemoveDuplicatedChunkRule.cs +++ b/BililiveRecorder.Flv/Pipeline/Rules/RemoveDuplicatedChunkRule.cs @@ -8,13 +8,8 @@ using StructLinq; namespace BililiveRecorder.Flv.Pipeline.Rules { /// - /// 删除重复的直播数据 + /// 删除重复的直播数据。 /// - /// - /// 通过对比直播数据的特征,删除重复的直播数据
- ///
- /// 本规则为一般规则 - ///
public class RemoveDuplicatedChunkRule : ISimpleProcessingRule { private const int MAX_HISTORY = 8; @@ -39,6 +34,7 @@ namespace BililiveRecorder.Flv.Pipeline.Rules unchecked { + // TODO: 改成用 Hash 判断 // 计算一个特征码 // 此处并没有遵循什么特定的算法,只是随便取了一些代表性比较强的值,用简单又尽量可靠的方式糅合到一起而已 foreach (var tag in data.Tags) diff --git a/BililiveRecorder.Flv/Pipeline/Rules/RemoveFillerDataRule.cs b/BililiveRecorder.Flv/Pipeline/Rules/RemoveFillerDataRule.cs index 77cd83f..ebc9496 100644 --- a/BililiveRecorder.Flv/Pipeline/Rules/RemoveFillerDataRule.cs +++ b/BililiveRecorder.Flv/Pipeline/Rules/RemoveFillerDataRule.cs @@ -4,14 +4,8 @@ using BililiveRecorder.Flv.Pipeline.Actions; namespace BililiveRecorder.Flv.Pipeline.Rules { /// - /// 删除 H.264 Filler Data + /// 删除 H.264 Filler Data,节省硬盘空间。 /// - /// - /// 部分直播码率瞎填的主播的直播数据中存在大量无用的 Filler Data
- /// 录制这些主播时删除这些数据可以节省硬盘空间
- ///
- /// 本规则应该放在一般规则前面 - ///
public class RemoveFillerDataRule : ISimpleProcessingRule { public void Run(FlvProcessingContext context, Action next) diff --git a/BililiveRecorder.Flv/Pipeline/Rules/UpdateTimestampJumpRule.cs b/BililiveRecorder.Flv/Pipeline/Rules/UpdateTimestampJumpRule.cs index 9ed3299..17913b7 100644 --- a/BililiveRecorder.Flv/Pipeline/Rules/UpdateTimestampJumpRule.cs +++ b/BililiveRecorder.Flv/Pipeline/Rules/UpdateTimestampJumpRule.cs @@ -7,6 +7,9 @@ using StructLinq; namespace BililiveRecorder.Flv.Pipeline.Rules { + /// + /// 修复时间戳跳变 + /// public class UpdateTimestampJumpRule : ISimpleProcessingRule { private const string TS_STORE_KEY = "Timestamp_Store_Key"; @@ -25,12 +28,14 @@ namespace BililiveRecorder.Flv.Pipeline.Rules { next(); + // 之前直播流的时间戳信息保存在 SessionItems 里 var ts = context.SessionItems.ContainsKey(TS_STORE_KEY) ? context.SessionItems[TS_STORE_KEY] as TimestampStore ?? new TimestampStore() : new TimestampStore(); context.SessionItems[TS_STORE_KEY] = ts; + // 按顺序处理每个 Action foreach (var action in context.Actions) { - if (action is PipelineDataAction dataAction) + if (action is PipelineDataAction dataAction) // 如果是直播数据,计算并调整时间戳 { // SetDataTimestamp var tags = dataAction.Tags; var currentTimestamp = tags[0].Timestamp; @@ -53,7 +58,7 @@ namespace BililiveRecorder.Flv.Pipeline.Rules ts.NextTimestampTarget = this.CalculateNewTarget(tags); } - else if (action is PipelineEndAction endAction) + else if (action is PipelineEndAction endAction) // End Tag 其实怎么处理都无所谓 { var tag = endAction.Tag; var diff = tag.Timestamp - ts.LastOriginal; @@ -66,16 +71,16 @@ namespace BililiveRecorder.Flv.Pipeline.Rules tag.Timestamp -= ts.CurrentOffset; } } - else if (action is PipelineNewFileAction) + else if (action is PipelineNewFileAction) // 如果新建文件分段了,重设时间戳信息重新从 0 开始 { ts.Reset(); } - else if (action is PipelineScriptAction s) + else if (action is PipelineScriptAction s) // Script Tag 时间戳永远为 0 { s.Tag.Timestamp = 0; ts.Reset(); } - else if (action is PipelineHeaderAction h) + else if (action is PipelineHeaderAction h) // Header Tag 时间戳永远为 0 { if (h.VideoHeader != null) h.VideoHeader.Timestamp = 0; @@ -86,6 +91,7 @@ namespace BililiveRecorder.Flv.Pipeline.Rules } } + // 计算理想情况下这段数据后面下一个 Tag 的时间戳应该是多少 [MethodImpl(MethodImplOptions.AggressiveInlining)] private int CalculateNewTarget(IReadOnlyList tags) { @@ -123,10 +129,19 @@ namespace BililiveRecorder.Flv.Pipeline.Rules private class TimestampStore { + /// + /// 下一个 Tag 的目标时间戳 + /// public int NextTimestampTarget; + /// + /// 上一个 Tag 的原始时间戳 + /// public int LastOriginal; + /// + /// 当前时间戳偏移量 + /// public int CurrentOffset; public void Reset() diff --git a/BililiveRecorder.Flv/Pipeline/Rules/UpdateTimestampOffsetRule.cs b/BililiveRecorder.Flv/Pipeline/Rules/UpdateTimestampOffsetRule.cs index 82e7ed6..d98636c 100644 --- a/BililiveRecorder.Flv/Pipeline/Rules/UpdateTimestampOffsetRule.cs +++ b/BililiveRecorder.Flv/Pipeline/Rules/UpdateTimestampOffsetRule.cs @@ -7,10 +7,13 @@ using StructLinq; namespace BililiveRecorder.Flv.Pipeline.Rules { + /// + /// 修复时间戳错位 + /// public class UpdateTimestampOffsetRule : ISimpleProcessingRule { - private static readonly ProcessingComment comment1 = new ProcessingComment(CommentType.Unrepairable, "GOP 内音频或视频时间戳不连续"); - private static readonly ProcessingComment comment2 = new ProcessingComment(CommentType.Unrepairable, "出现了无法计算偏移量的音视频偏移"); + private static readonly ProcessingComment COMMENT_JumpedWithinGOP = new ProcessingComment(CommentType.Unrepairable, "GOP 内音频或视频时间戳不连续"); + private static readonly ProcessingComment COMMENT_CantSolve = new ProcessingComment(CommentType.Unrepairable, "出现了无法计算偏移量的音视频偏移"); public void Run(FlvProcessingContext context, Action next) { @@ -18,9 +21,12 @@ namespace BililiveRecorder.Flv.Pipeline.Rules next(); } - private readonly struct IsNotNormal : ITwoInputFunction + /// + /// 检查 Tag 时间戳是否有变小的情况 + /// + private readonly struct IsNextTimestampSmaller : ITwoInputFunction { - public static IsNotNormal Instance; + public static IsNextTimestampSmaller Instance; public bool Eval(Tag a, Tag b) => a.Timestamp > b.Timestamp; } @@ -28,19 +34,19 @@ namespace BililiveRecorder.Flv.Pipeline.Rules { if (action is PipelineDataAction data) { - var isNotNormal = data.Tags.Any2(ref IsNotNormal.Instance); + var isNotNormal = data.Tags.Any2(ref IsNextTimestampSmaller.Instance); if (!isNotNormal) { - // 没有问题 + // 没有问题,每个 tag 的时间戳都 >= 上一个 tag 的时间戳。 yield return data; yield break; } - if (data.Tags.Where(x => x.Type == TagType.Audio).Any2(ref IsNotNormal.Instance) || data.Tags.Where(x => x.Type == TagType.Video).Any2(ref IsNotNormal.Instance)) + if (data.Tags.Where(x => x.Type == TagType.Audio).Any2(ref IsNextTimestampSmaller.Instance) || data.Tags.Where(x => x.Type == TagType.Video).Any2(ref IsNextTimestampSmaller.Instance)) { // 音频或视频自身就有问题,没救了 yield return PipelineDisconnectAction.Instance; - context.AddComment(comment1); + context.AddComment(COMMENT_JumpedWithinGOP); yield break; } else @@ -150,7 +156,7 @@ namespace BililiveRecorder.Flv.Pipeline.Rules yield break; invalidOffset: - context.AddComment(comment2); + context.AddComment(COMMENT_CantSolve); yield return PipelineDisconnectAction.Instance; yield break; }