FLV: Update tag grouping

This commit is contained in:
Genteure 2021-04-02 20:44:17 +08:00
parent 7c82019c5c
commit 68a6eaa275
6 changed files with 88 additions and 43 deletions

View File

@ -7,15 +7,17 @@ namespace BililiveRecorder.Flv.Grouping.Rules
{
public class DataGroupingRule : IGroupingRule
{
public bool StartWith(List<Tag> tags) => tags.Count > 0 && tags[0].IsData();
public bool StartWith(Tag tag) => tag.IsData();
public bool AppendWith(Tag tag, List<Tag> tags, out List<Tag>? leftover)
public bool AppendWith(Tag tag, LinkedList<Tag> tags, out LinkedList<Tag>? 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<Tag>();
leftover.AddRange(tags.Where(predicate));
leftover.Add(tag);
tags.RemoveAll(predicate);
return false;
leftover = new LinkedList<Tag>();
foreach (var item in tags.Where(predicate))
leftover.AddLast(item);
leftover.AddLast(tag);
}
// tags.RemoveAll(predicate);
{
var node = tags.First;
while (node != null)
{
var next = node.Next;
if (predicate(node.Value))
tags.Remove(node);
node = next;
}
}
leftover = new List<Tag> { tag };
return false;
}
else
{
leftover = new LinkedList<Tag>();
leftover.AddLast(tag);
return false;
}
}
}
public PipelineAction CreatePipelineAction(List<Tag> tags) => new PipelineDataAction(tags);
public PipelineAction CreatePipelineAction(LinkedList<Tag> tags) => new PipelineDataAction(new List<Tag>(tags));
}
}

View File

@ -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<Tag> tags) => tags.Count == 1 && tags[0].IsEnd();
public bool StartWith(Tag tag) => tag.IsEnd();
public bool AppendWith(Tag tag, List<Tag> tags, out List<Tag>? leftover)
public bool AppendWith(Tag tag, LinkedList<Tag> tags, out LinkedList<Tag>? leftover)
{
leftover = new List<Tag> { tag };
leftover = new LinkedList<Tag>();
leftover.AddLast(tag);
return false;
}
public PipelineAction CreatePipelineAction(List<Tag> tags) => new PipelineEndAction(tags.First());
public PipelineAction CreatePipelineAction(LinkedList<Tag> tags) => new PipelineEndAction(tags.First.Value);
}
}

View File

@ -5,23 +5,24 @@ namespace BililiveRecorder.Flv.Grouping.Rules
{
public class HeaderGroupingRule : IGroupingRule
{
public bool StartWith(List<Tag> tags) => tags.Count > 0 && tags.TrueForAll(x => x.IsHeader());
public bool StartWith(Tag tag) => tag.IsHeader();
public bool AppendWith(Tag tag, List<Tag> tags, out List<Tag>? leftover)
public bool AppendWith(Tag tag, LinkedList<Tag> tags, out LinkedList<Tag>? leftover)
{
if (tag.IsHeader())
{
tags.Add(tag);
tags.AddLast(tag);
leftover = null;
return true;
}
else
{
leftover = new List<Tag> { tag };
leftover = new LinkedList<Tag>();
leftover.AddLast(tag);
return false;
}
}
public PipelineAction CreatePipelineAction(List<Tag> tags) => new PipelineHeaderAction(tags);
public PipelineAction CreatePipelineAction(LinkedList<Tag> tags) => new PipelineHeaderAction(new List<Tag>(tags));
}
}

View File

@ -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<Tag> tags) => tags.Count == 1 && tags[0].IsScript();
public bool StartWith(Tag tag) => tag.IsScript();
public bool AppendWith(Tag tag, List<Tag> tags, out List<Tag>? leftover)
public bool AppendWith(Tag tag, LinkedList<Tag> tags, out LinkedList<Tag>? leftover)
{
leftover = new List<Tag> { tag };
leftover = new LinkedList<Tag>();
leftover.AddLast(tag);
return false;
}
public PipelineAction CreatePipelineAction(List<Tag> tags) => new PipelineScriptAction(tags.First());
public PipelineAction CreatePipelineAction(LinkedList<Tag> tags) => new PipelineScriptAction(tags.First.Value);
}
}

View File

@ -14,7 +14,7 @@ namespace BililiveRecorder.Flv.Grouping
private readonly bool leaveOpen;
private bool disposedValue;
private List<Tag>? leftover;
private LinkedList<Tag>? leftover;
public IFlvTagReader TagReader { get; }
public IList<IGroupingRule> GroupingRules { get; }
@ -45,39 +45,65 @@ namespace BililiveRecorder.Flv.Grouping
}
try
{
List<Tag> tags;
LinkedList<Tag>? 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<Tag> { 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<Tag>();
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

View File

@ -10,7 +10,7 @@ namespace BililiveRecorder.Flv
/// </summary>
/// <param name="tags">Current Tags</param>
/// <returns></returns>
bool StartWith(List<Tag> tags);
bool StartWith(Tag tag);
/// <summary>
///
@ -19,8 +19,8 @@ namespace BililiveRecorder.Flv
/// <param name="tags">List of tags</param>
/// <param name="leftover"></param>
/// <returns></returns>
bool AppendWith(Tag tag, List<Tag> tags, out List<Tag>? leftover);
bool AppendWith(Tag tag, LinkedList<Tag> tags, out LinkedList<Tag>? leftover);
PipelineAction CreatePipelineAction(List<Tag> tags);
PipelineAction CreatePipelineAction(LinkedList<Tag> tags);
}
}