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;
}