From 68a6eaa2759065820f33b3d18ed9da91732c80ae Mon Sep 17 00:00:00 2001 From: Genteure Date: Fri, 2 Apr 2021 20:44:17 +0800 Subject: [PATCH] FLV: Update tag grouping --- .../Grouping/Rules/DataGroupingRule.cs | 48 +++++++++++++------ .../Grouping/Rules/EndGroupingRule.cs | 10 ++-- .../Grouping/Rules/HeaderGroupingRule.cs | 11 +++-- .../Grouping/Rules/ScriptGroupingRule.cs | 10 ++-- .../Grouping/TagGroupReader.cs | 46 ++++++++++++++---- BililiveRecorder.Flv/IGroupingRule.cs | 6 +-- 6 files changed, 88 insertions(+), 43 deletions(-) diff --git a/BililiveRecorder.Flv/Grouping/Rules/DataGroupingRule.cs b/BililiveRecorder.Flv/Grouping/Rules/DataGroupingRule.cs index 97622e9..ba8c98b 100644 --- a/BililiveRecorder.Flv/Grouping/Rules/DataGroupingRule.cs +++ b/BililiveRecorder.Flv/Grouping/Rules/DataGroupingRule.cs @@ -7,15 +7,17 @@ namespace BililiveRecorder.Flv.Grouping.Rules { public class DataGroupingRule : IGroupingRule { - public bool StartWith(List tags) => tags.Count > 0 && tags[0].IsData(); + public bool StartWith(Tag tag) => tag.IsData(); - public bool AppendWith(Tag tag, List tags, out List? leftover) + public bool AppendWith(Tag tag, LinkedList tags, out LinkedList? leftover) { - var flag = tag.IsNonKeyframeData() || (tag.Type == TagType.Audio && tag.Flag == TagFlag.Header && tags.TrueForAll(x => x.Type != TagType.Audio)); + var flag = tag.IsNonKeyframeData() + || (tag.IsKeyframeData() && tags.All(x => x.IsNonKeyframeData())) + || (tag.Type == TagType.Audio && tag.Flag == TagFlag.Header && tags.All(x => x.Type != TagType.Audio || x.Flag == TagFlag.Header)); if (flag) { - tags.Add(tag); + tags.AddLast(tag); leftover = null; return true; } @@ -23,25 +25,41 @@ namespace BililiveRecorder.Flv.Grouping.Rules { var ts = tag.Timestamp; var lastAudio = tags.LastOrDefault(x => x.Type == TagType.Audio); + bool predicate(Tag x) => x.Type == TagType.Audio && x.Timestamp >= ts; - if (tag.IsKeyframeData()) + if (tag.IsKeyframeData() && lastAudio is not null && Math.Abs(tag.Timestamp - lastAudio.Timestamp) <= 50 && tags.Any(predicate)) { - if (lastAudio is not null && Math.Abs(tag.Timestamp - lastAudio.Timestamp) <= 50 && tags.Any(predicate)) { - leftover = new List(); - leftover.AddRange(tags.Where(predicate)); - leftover.Add(tag); - tags.RemoveAll(predicate); - return false; + leftover = new LinkedList(); + foreach (var item in tags.Where(predicate)) + leftover.AddLast(item); + leftover.AddLast(tag); } - } - leftover = new List { tag }; - return false; + // tags.RemoveAll(predicate); + { + var node = tags.First; + while (node != null) + { + var next = node.Next; + if (predicate(node.Value)) + tags.Remove(node); + node = next; + } + } + + return false; + } + else + { + leftover = new LinkedList(); + leftover.AddLast(tag); + return false; + } } } - public PipelineAction CreatePipelineAction(List tags) => new PipelineDataAction(tags); + public PipelineAction CreatePipelineAction(LinkedList tags) => new PipelineDataAction(new List(tags)); } } diff --git a/BililiveRecorder.Flv/Grouping/Rules/EndGroupingRule.cs b/BililiveRecorder.Flv/Grouping/Rules/EndGroupingRule.cs index 0268c3b..f408cf0 100644 --- a/BililiveRecorder.Flv/Grouping/Rules/EndGroupingRule.cs +++ b/BililiveRecorder.Flv/Grouping/Rules/EndGroupingRule.cs @@ -1,19 +1,19 @@ using System.Collections.Generic; -using System.Linq; using BililiveRecorder.Flv.Pipeline; namespace BililiveRecorder.Flv.Grouping.Rules { public class EndGroupingRule : IGroupingRule { - public bool StartWith(List tags) => tags.Count == 1 && tags[0].IsEnd(); + public bool StartWith(Tag tag) => tag.IsEnd(); - public bool AppendWith(Tag tag, List tags, out List? leftover) + public bool AppendWith(Tag tag, LinkedList tags, out LinkedList? leftover) { - leftover = new List { tag }; + leftover = new LinkedList(); + leftover.AddLast(tag); return false; } - public PipelineAction CreatePipelineAction(List tags) => new PipelineEndAction(tags.First()); + public PipelineAction CreatePipelineAction(LinkedList tags) => new PipelineEndAction(tags.First.Value); } } diff --git a/BililiveRecorder.Flv/Grouping/Rules/HeaderGroupingRule.cs b/BililiveRecorder.Flv/Grouping/Rules/HeaderGroupingRule.cs index d64d30c..46b381f 100644 --- a/BililiveRecorder.Flv/Grouping/Rules/HeaderGroupingRule.cs +++ b/BililiveRecorder.Flv/Grouping/Rules/HeaderGroupingRule.cs @@ -5,23 +5,24 @@ namespace BililiveRecorder.Flv.Grouping.Rules { public class HeaderGroupingRule : IGroupingRule { - public bool StartWith(List tags) => tags.Count > 0 && tags.TrueForAll(x => x.IsHeader()); + public bool StartWith(Tag tag) => tag.IsHeader(); - public bool AppendWith(Tag tag, List tags, out List? leftover) + public bool AppendWith(Tag tag, LinkedList tags, out LinkedList? leftover) { if (tag.IsHeader()) { - tags.Add(tag); + tags.AddLast(tag); leftover = null; return true; } else { - leftover = new List { tag }; + leftover = new LinkedList(); + leftover.AddLast(tag); return false; } } - public PipelineAction CreatePipelineAction(List tags) => new PipelineHeaderAction(tags); + public PipelineAction CreatePipelineAction(LinkedList tags) => new PipelineHeaderAction(new List(tags)); } } diff --git a/BililiveRecorder.Flv/Grouping/Rules/ScriptGroupingRule.cs b/BililiveRecorder.Flv/Grouping/Rules/ScriptGroupingRule.cs index 9f79baf..5166fbd 100644 --- a/BililiveRecorder.Flv/Grouping/Rules/ScriptGroupingRule.cs +++ b/BililiveRecorder.Flv/Grouping/Rules/ScriptGroupingRule.cs @@ -1,19 +1,19 @@ using System.Collections.Generic; -using System.Linq; using BililiveRecorder.Flv.Pipeline; namespace BililiveRecorder.Flv.Grouping.Rules { public class ScriptGroupingRule : IGroupingRule { - public bool StartWith(List tags) => tags.Count == 1 && tags[0].IsScript(); + public bool StartWith(Tag tag) => tag.IsScript(); - public bool AppendWith(Tag tag, List tags, out List? leftover) + public bool AppendWith(Tag tag, LinkedList tags, out LinkedList? leftover) { - leftover = new List { tag }; + leftover = new LinkedList(); + leftover.AddLast(tag); return false; } - public PipelineAction CreatePipelineAction(List tags) => new PipelineScriptAction(tags.First()); + public PipelineAction CreatePipelineAction(LinkedList tags) => new PipelineScriptAction(tags.First.Value); } } diff --git a/BililiveRecorder.Flv/Grouping/TagGroupReader.cs b/BililiveRecorder.Flv/Grouping/TagGroupReader.cs index ef0a68d..279f957 100644 --- a/BililiveRecorder.Flv/Grouping/TagGroupReader.cs +++ b/BililiveRecorder.Flv/Grouping/TagGroupReader.cs @@ -14,7 +14,7 @@ namespace BililiveRecorder.Flv.Grouping private readonly bool leaveOpen; private bool disposedValue; - private List? leftover; + private LinkedList? leftover; public IFlvTagReader TagReader { get; } public IList GroupingRules { get; } @@ -45,39 +45,65 @@ namespace BililiveRecorder.Flv.Grouping } try { - List tags; + LinkedList? queue = null; + Tag? firstTag; - if (this.leftover is not null) + if (this.leftover is not null && this.leftover.Count > 0) { - tags = this.leftover; + queue = this.leftover; this.leftover = null; + + firstTag = queue.First.Value; + queue.RemoveFirst(); } else { - var firstTag = await this.TagReader.ReadTagAsync(token).ConfigureAwait(false); + firstTag = await this.TagReader.ReadTagAsync(token).ConfigureAwait(false); // 数据已经全部读完 if (firstTag is null) return null; - - tags = new List { firstTag }; } - var rule = this.GroupingRules.FirstOrDefault(x => x.StartWith(tags)); + var rule = this.GroupingRules.FirstOrDefault(x => x.StartWith(firstTag)); if (rule is null) - throw new Exception("No grouping rule accepting tags:\n" + string.Join("\n", tags.Select(x => x.ToString()))); + throw new Exception("No grouping rule accepting tags: " + firstTag.ToString()); + + var tags = new LinkedList(); + tags.AddLast(firstTag); while (!token.IsCancellationRequested) { - var tag = await this.TagReader.ReadTagAsync(token).ConfigureAwait(false); + Tag? tag; + + if (queue is not null && queue.Count > 0) + { + tag = queue.First.Value; + queue.RemoveFirst(); + } + else + { + tag = await this.TagReader.ReadTagAsync(token).ConfigureAwait(false); + } if (tag == null || !rule.AppendWith(tag, tags, out this.leftover)) { + if (queue is not null && queue.Count > 0) + { + if (this.leftover is null) + this.leftover = queue; + else + foreach (var item in queue) + this.leftover.AddLast(item); + } break; } } + if (tags.Count == 0) + throw new Exception("TagGroup tag count is 0"); + return rule.CreatePipelineAction(tags); } finally diff --git a/BililiveRecorder.Flv/IGroupingRule.cs b/BililiveRecorder.Flv/IGroupingRule.cs index 60ae15a..60b273f 100644 --- a/BililiveRecorder.Flv/IGroupingRule.cs +++ b/BililiveRecorder.Flv/IGroupingRule.cs @@ -10,7 +10,7 @@ namespace BililiveRecorder.Flv /// /// Current Tags /// - bool StartWith(List tags); + bool StartWith(Tag tag); /// /// @@ -19,8 +19,8 @@ namespace BililiveRecorder.Flv /// List of tags /// /// - bool AppendWith(Tag tag, List tags, out List? leftover); + bool AppendWith(Tag tag, LinkedList tags, out LinkedList? leftover); - PipelineAction CreatePipelineAction(List tags); + PipelineAction CreatePipelineAction(LinkedList tags); } }