Example #1
0
        private static void CheckTimelineCoverage(SegmentTemplate template, DateTimeOffset windowStart, DateTimeOffset windowEnd, string path, IFeedbackSink feedback)
        {
            var period             = template.ResolveAdaptationSet().Period;
            var periodTimingString = $"The period lasts from {period.Start.ToTimeStringAccurate()} to {(period.End ?? windowEnd).ToTimeStringAccurate()}.";

            var contentExistsUpTo = period.Start;

            // Skip until playback window start. This may even mean skipping the entire period.
            if (windowStart > contentExistsUpTo)
            {
                feedback.Info("Skipping data that lies before the playback window start.");
                contentExistsUpTo = windowStart;
            }

            var ignoredPastSegments   = 0;
            var ignoredFutureSegments = 0;

            foreach (var segment in template.Segments)
            {
                // If it is entirely in the past, skip it.
                if (segment.End <= contentExistsUpTo)
                {
                    ignoredPastSegments++;
                    continue;
                }

                // If it leaves a gap, scream.
                if (segment.Start > contentExistsUpTo)
                {
                    var gapLength = segment.Start - contentExistsUpTo;
                    var playbackWindowStartString = contentExistsUpTo == windowStart ? " This gap is at the start of the playback window." : "";

                    feedback.InvalidContent($"There is a gap of {gapLength.TotalMilliseconds:F1} ms from {contentExistsUpTo.ToTimeStringAccurate()} to {segment.Start.ToTimeStringAccurate()} in {path}. {periodTimingString}{playbackWindowStartString}");
                }

                // If the segment is entirely in the future, skip it.
                // This can be either because this period was cut short by a new period
                // or because this is the last period and the described segment is not available yet.
                if (segment.Start > (period.End ?? windowEnd))
                {
                    ignoredFutureSegments++;
                    continue;
                }

                // Mark as contentful time segment.
                contentExistsUpTo = segment.End;

                // If we overshot period end, clip back.
                if (period.End.HasValue && contentExistsUpTo > period.End)
                {
                    contentExistsUpTo = period.End.Value;
                }
            }

            if (period.End.HasValue)
            {
                // Make sure we covered the period until the end if we know its end.
                if (contentExistsUpTo != period.End.Value)
                {
                    var gapLength = period.End.Value - contentExistsUpTo;
                    feedback.InvalidContent($"There is a gap of {gapLength.TotalMilliseconds:F1} ms from {contentExistsUpTo.ToTimeStringAccurate()} to {period.End.Value.ToTimeStringAccurate()} in {path}. {periodTimingString} This gap is at the end of the period.");
                }
            }
            else
            {
                // Make sure we covered the period until playback window end if we do not know period end.
                if (contentExistsUpTo < windowEnd)
                {
                    var gapLength = windowEnd - contentExistsUpTo;
                    feedback.InvalidContent($"There is a gap of {gapLength.TotalMilliseconds:F1} ms from {contentExistsUpTo.ToTimeStringAccurate()} to {windowEnd.ToTimeStringAccurate()}. {periodTimingString} This gap is at the end of the period.");
                }
            }

            if (ignoredPastSegments != 0 || ignoredFutureSegments != 0)
            {
                feedback.Info($"Ignored {ignoredPastSegments} segments that were too early and would never be played. Ignored {ignoredFutureSegments} segments that were too late and would never be played.");
            }
        }