Browse Source

treat mid-roll as post-roll when chapter markers are missing (#1722)

pull/1723/head
Jason Dove 1 year ago committed by GitHub
parent
commit
7c1f0d6dbd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 41
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs
  3. 28
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs

2
CHANGELOG.md

@ -86,6 +86,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -86,6 +86,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix block playout random seeds
- Different blocks within a single playout will now correctly use different random seeds (shuffles)
- Erasing block playout history will also generate new random seeds for the playout
- Fix building playouts that use mid-roll filler and have content without chapter markers
- When this happens, mid-roll will be treated as post-roll
### Changed
- Use ffmpeg 7 in all docker images

41
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs

@ -243,7 +243,41 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe @@ -243,7 +243,41 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
List<MediaChapter> effectiveChapters = chapters;
if (allFiller.All(fp => fp.FillerKind != FillerKind.MidRoll) || effectiveChapters.Count <= 1)
{
effectiveChapters = new List<MediaChapter>();
effectiveChapters = [];
}
// convert mid-roll to post-roll if we have no chapters
if (allFiller.Any(f => f.FillerKind is FillerKind.MidRoll) && effectiveChapters.Count == 0)
{
Logger.LogInformation(
"Converting mid-roll filler preset to post-roll for content that has no chapter markers");
var toRemove = allFiller.Filter(f => f.FillerKind is FillerKind.MidRoll).ToList();
allFiller.RemoveAll(toRemove.Contains);
foreach (FillerPreset midRollFiller in toRemove)
{
var clone = new FillerPreset
{
FillerKind = FillerKind.PostRoll,
FillerMode = midRollFiller.FillerMode,
Duration = midRollFiller.Duration,
Count = midRollFiller.Count,
PadToNearestMinute = midRollFiller.PadToNearestMinute,
AllowWatermarks = midRollFiller.AllowWatermarks,
CollectionType = midRollFiller.CollectionType,
CollectionId = midRollFiller.CollectionId,
Collection = midRollFiller.Collection,
MediaItemId = midRollFiller.MediaItemId,
MediaItem = midRollFiller.MediaItem,
MultiCollectionId = midRollFiller.MultiCollectionId,
MultiCollection = midRollFiller.MultiCollection,
SmartCollectionId = midRollFiller.SmartCollectionId,
SmartCollection = midRollFiller.SmartCollection
};
allFiller.Add(clone);
}
}
foreach (FillerPreset filler in allFiller.Filter(
@ -395,10 +429,11 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe @@ -395,10 +429,11 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
TimeSpan remainingToFill = targetTime - totalDuration - playoutItem.StartOffset;
// _logger.LogInformation(
// "Total duration {TotalDuration}; need to fill {TimeSpan} to pad properly to {TargetTime}",
// Logger.LogInformation(
// "Total duration {TotalDuration}; need to fill {TimeSpan} to pad properly from {StartTime} to {TargetTime}",
// totalDuration,
// remainingToFill,
// playoutItem.StartOffset,
// targetTime);
switch (padFiller.FillerKind)

28
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs

@ -20,6 +20,13 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche @@ -20,6 +20,13 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche
DateTimeOffset hardStop,
CancellationToken cancellationToken)
{
// Logger.LogDebug(
// "DurationSchedule: {CurrentTime} {DurationFinish} {InDurationFiller} {HardStop}",
// playoutBuilderState.CurrentTime,
// playoutBuilderState.DurationFinish,
// playoutBuilderState.InDurationFiller,
// hardStop);
var playoutItems = new List<PlayoutItem>();
PlayoutBuilderState nextState = playoutBuilderState;
@ -30,8 +37,16 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche @@ -30,8 +37,16 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche
IMediaCollectionEnumerator contentEnumerator =
collectionEnumerators[CollectionKey.ForScheduleItem(scheduleItem)];
while (contentEnumerator.Current.IsSome && nextState.CurrentTime < hardStop && willFinishInTime)
while (contentEnumerator.Current.IsSome && nextState.CurrentTime < hardStop && willFinishInTime &&
nextState.CurrentTime < nextState.DurationFinish.IfNone(SystemTime.MaxValueUtc))
{
// Logger.LogDebug(
// "Duration Loop: CT: {CurrentTime} DF: {DurationFinish} Filler: {InDurationFiller} Stop: {HardStop}",
// nextState.CurrentTime,
// nextState.DurationFinish,
// nextState.InDurationFiller,
// hardStop);
MediaItem mediaItem = contentEnumerator.Current.ValueUnsafe();
// find when we should start this item, based on the current time
@ -50,6 +65,8 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche @@ -50,6 +65,8 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche
{
DurationFinish = itemStartTime + scheduleItem.PlayoutDuration
};
// Logger.LogDebug("Setting duration finish to {DurationFinish}", nextState.DurationFinish);
}
durationUntil = nextState.DurationFinish;
@ -138,6 +155,15 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche @@ -138,6 +155,15 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche
false,
cancellationToken);
// foreach (PlayoutItem pi in maybePlayoutItems.OrderBy(pi => pi.StartOffset))
// {
// Logger.LogDebug(
// " - PI Start: {Start} - {Id} - {FillerKind}",
// pi.StartOffset,
// pi.MediaItemId,
// pi.FillerKind);
// }
DateTimeOffset itemEndTimeWithFiller = maybePlayoutItems.Max(pi => pi.FinishOffset);
willFinishInTime = itemStartTime > durationFinish ||

Loading…
Cancel
Save