FLV: Small adjustments

This commit is contained in:
genteure 2022-05-02 00:01:41 +08:00
parent 0f70c6c78d
commit dd7266a54f
9 changed files with 44 additions and 43 deletions

View File

@ -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

View File

@ -7,11 +7,8 @@ using StructLinq;
namespace BililiveRecorder.Flv.Pipeline.Rules
{
/// <summary>
/// 处理延后收到的音频头
/// 处理延后收到的音频头,移动到音视频数据的前面。
/// </summary>
/// <remarks>
/// 本规则应该放在所有规则前面
/// </remarks>
public class HandleDelayedAudioHeaderRule : ISimpleProcessingRule
{
private static readonly ProcessingComment comment1 = new ProcessingComment(CommentType.Unrepairable, "音频数据出现在音频头之前");

View File

@ -5,7 +5,7 @@ using BililiveRecorder.Flv.Pipeline.Actions;
namespace BililiveRecorder.Flv.Pipeline.Rules
{
/// <summary>
/// 处理 end tag
/// 处理 End Tag遇到的时候对文件进行分段
/// </summary>
public class HandleEndTagRule : ISimpleProcessingRule
{

View File

@ -8,14 +8,8 @@ using StructLinq.Where;
namespace BililiveRecorder.Flv.Pipeline.Rules
{
/// <summary>
/// 处理收到音视频 Header 的情况
/// 处理音视频 Header。收到音视频 Header 时检查与上一组是否相同,并根据情况删除重复的 Header 或新建文件。<br/>
/// </summary>
/// <remarks>
/// 当收到音视频 Header 时检查与上一组是否相同<br/>
/// 并根据情况删除重复的 Header 或新建文件写入<br/>
/// <br/>
/// 本规则为一般规则
/// </remarks>
public class HandleNewHeaderRule : ISimpleProcessingRule
{
private const string VIDEO_HEADER_KEY = "HandleNewHeaderRule_VideoHeader";

View File

@ -6,11 +6,8 @@ using BililiveRecorder.Flv.Pipeline.Actions;
namespace BililiveRecorder.Flv.Pipeline.Rules
{
/// <summary>
/// 处理收到 Script Tag 的情况
/// 处理 Script Tag
/// </summary>
/// <remarks>
/// 本规则为一般规则
/// </remarks>
public class HandleNewScriptRule : ISimpleProcessingRule
{
private const string onMetaData = "onMetaData";

View File

@ -8,13 +8,8 @@ using StructLinq;
namespace BililiveRecorder.Flv.Pipeline.Rules
{
/// <summary>
/// 删除重复的直播数据
/// 删除重复的直播数据
/// </summary>
/// <remarks>
/// 通过对比直播数据的特征,删除重复的直播数据<br/>
/// <br/>
/// 本规则为一般规则
/// </remarks>
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)

View File

@ -4,14 +4,8 @@ using BililiveRecorder.Flv.Pipeline.Actions;
namespace BililiveRecorder.Flv.Pipeline.Rules
{
/// <summary>
/// 删除 H.264 Filler Data
/// 删除 H.264 Filler Data,节省硬盘空间。
/// </summary>
/// <remarks>
/// 部分直播码率瞎填的主播的直播数据中存在大量无用的 Filler Data<br/>
/// 录制这些主播时删除这些数据可以节省硬盘空间<br/>
/// <br/>
/// 本规则应该放在一般规则前面
/// </remarks>
public class RemoveFillerDataRule : ISimpleProcessingRule
{
public void Run(FlvProcessingContext context, Action next)

View File

@ -7,6 +7,9 @@ using StructLinq;
namespace BililiveRecorder.Flv.Pipeline.Rules
{
/// <summary>
/// 修复时间戳跳变
/// </summary>
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<Tag> tags)
{
@ -123,10 +129,19 @@ namespace BililiveRecorder.Flv.Pipeline.Rules
private class TimestampStore
{
/// <summary>
/// 下一个 Tag 的目标时间戳
/// </summary>
public int NextTimestampTarget;
/// <summary>
/// 上一个 Tag 的原始时间戳
/// </summary>
public int LastOriginal;
/// <summary>
/// 当前时间戳偏移量
/// </summary>
public int CurrentOffset;
public void Reset()

View File

@ -7,10 +7,13 @@ using StructLinq;
namespace BililiveRecorder.Flv.Pipeline.Rules
{
/// <summary>
/// 修复时间戳错位
/// </summary>
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, bool>
/// <summary>
/// 检查 Tag 时间戳是否有变小的情况
/// </summary>
private readonly struct IsNextTimestampSmaller : ITwoInputFunction<Tag, bool>
{
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;
}