using System; using System.Collections.Generic; using System.Linq; using BililiveRecorder.Flv.Pipeline.Actions; using StructLinq; namespace BililiveRecorder.Flv.Pipeline.Rules { /// /// 处理延后收到的音频头,移动到音视频数据的前面。 /// public class HandleDelayedAudioHeaderRule : ISimpleProcessingRule { private static readonly ProcessingComment comment1 = new ProcessingComment(CommentType.Unrepairable, true, "音频数据出现在音频头之前"); private static readonly ProcessingComment comment2 = new ProcessingComment(CommentType.DecodingHeader, true, "检测到延后收到的音频头"); public void Run(FlvProcessingContext context, Action next) { context.PerActionRun(this.RunPerAction); next(); } private IEnumerable RunPerAction(FlvProcessingContext context, PipelineAction action) { if (action is PipelineDataAction data) { var tags = data.Tags; // 如果分组内含有 Heaer if (tags.ToStructEnumerable().Any(ref LinqFunctions.TagIsHeader, x => x)) { { var shouldReportError = false; for (var i = tags.Count - 1; i >= 0; i--) { if (tags[i].Type == TagType.Audio) { if (tags[i].Flag != TagFlag.None) { // 发现了 Audio Header shouldReportError = true; } else { // 在一段数据内 Header 之前出现了音频数据 if (shouldReportError) { context.AddComment(comment1); yield return new PipelineDisconnectAction("直播音频数据中间出现音频头"); yield return PipelineNewFileAction.Instance; yield return null; yield break; } } } } } context.AddComment(comment2); var headerTags = tags.ToStructEnumerable().Where(ref LinqFunctions.TagIsHeader, x => x).ToArray(); var newHeaderAction = new PipelineHeaderAction(headerTags); var dataTags = tags.ToStructEnumerable().Except(headerTags.ToStructEnumerable(), x => x, x => x).ToArray(); var newDataAction = new PipelineDataAction(dataTags); yield return newHeaderAction; yield return newDataAction; } else yield return data; } else yield return action; } } }