use output duration flag (#49)

* re-enable output duration flag

* calculate appropriate duration for offline image
This commit is contained in:
Jason Dove
2021-03-08 11:16:56 +00:00
committed by GitHub
parent 9841640128
commit 5244d5076a
5 changed files with 34 additions and 18 deletions
@@ -10,7 +10,6 @@ using ErsatzTV.Core.FFmpeg;
using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt; using LanguageExt;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using static LanguageExt.Prelude;
namespace ErsatzTV.Application.Streaming.Queries namespace ErsatzTV.Application.Streaming.Queries
{ {
@@ -69,18 +68,20 @@ namespace ErsatzTV.Application.Streaming.Queries
playoutItem.StartOffset, playoutItem.StartOffset,
now); now);
}, },
() => async () =>
{ {
if (channel.FFmpegProfile.Transcode) if (channel.FFmpegProfile.Transcode)
{ {
return Right<BaseError, Process>(_ffmpegProcessService.ForOfflineImage(ffmpegPath, channel)) Option<TimeSpan> maybeDuration = await _playoutRepository.GetNextItemStart(channel.Id, now)
.AsTask(); .MapT(nextStart => nextStart - now);
return _ffmpegProcessService.ForOfflineImage(ffmpegPath, channel, maybeDuration);
} }
var message = var message =
$"Unable to locate playout item for channel {channel.Number}; offline image is unavailable because transcoding is disabled in ffmpeg profile '{channel.FFmpegProfile.Name}'"; $"Unable to locate playout item for channel {channel.Number}; offline image is unavailable because transcoding is disabled in ffmpeg profile '{channel.FFmpegProfile.Name}'";
return Left<BaseError, Process>(BaseError.New(message)).AsTask(); return BaseError.New(message);
}); });
} }
+6 -4
View File
@@ -227,10 +227,12 @@ namespace ErsatzTV.Core.FFmpeg
"1:a"); "1:a");
} }
public FFmpegProcessBuilder WithDuration(TimeSpan duration) => public FFmpegProcessBuilder WithDuration(TimeSpan duration)
// _arguments.Add("-t"); {
// _arguments.Add($"{duration:c}"); _arguments.Add("-t");
this; _arguments.Add($"{duration:c}");
return this;
}
public FFmpegProcessBuilder WithFormat(string format) public FFmpegProcessBuilder WithFormat(string format)
{ {
+8 -6
View File
@@ -2,6 +2,7 @@
using System.Diagnostics; using System.Diagnostics;
using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.FFmpeg; using ErsatzTV.Core.Interfaces.FFmpeg;
using LanguageExt;
namespace ErsatzTV.Core.FFmpeg namespace ErsatzTV.Core.FFmpeg
{ {
@@ -83,14 +84,14 @@ namespace ErsatzTV.Core.FFmpeg
.Build(); .Build();
} }
public Process ForOfflineImage(string ffmpegPath, Channel channel) public Process ForOfflineImage(string ffmpegPath, Channel channel, Option<TimeSpan> duration)
{ {
FFmpegPlaybackSettings playbackSettings = FFmpegPlaybackSettings playbackSettings =
_playbackSettingsCalculator.CalculateErrorSettings(channel.FFmpegProfile); _playbackSettingsCalculator.CalculateErrorSettings(channel.FFmpegProfile);
IDisplaySize desiredResolution = channel.FFmpegProfile.Resolution; IDisplaySize desiredResolution = channel.FFmpegProfile.Resolution;
return new FFmpegProcessBuilder(ffmpegPath) FFmpegProcessBuilder builder = new FFmpegProcessBuilder(ffmpegPath)
.WithThreads(1) .WithThreads(1)
.WithQuiet() .WithQuiet()
.WithFormatFlags(playbackSettings.FormatFlags) .WithFormatFlags(playbackSettings.FormatFlags)
@@ -102,10 +103,11 @@ namespace ErsatzTV.Core.FFmpeg
.WithPixfmt("yuv420p") .WithPixfmt("yuv420p")
.WithPlaybackArgs(playbackSettings) .WithPlaybackArgs(playbackSettings)
.WithMetadata(channel) .WithMetadata(channel)
.WithFormat("mpegts") .WithFormat("mpegts");
.WithDuration(TimeSpan.FromSeconds(10)) // TODO: figure out when we're back online
.WithPipe() duration.IfSome(d => builder = builder.WithDuration(d));
.Build();
return builder.WithPipe().Build();
} }
public Process ConcatChannel(string ffmpegPath, Channel channel, string scheme, string host) public Process ConcatChannel(string ffmpegPath, Channel channel, string scheme, string host)
@@ -12,6 +12,7 @@ namespace ErsatzTV.Core.Interfaces.Repositories
Task<Option<Playout>> Get(int id); Task<Option<Playout>> Get(int id);
Task<Option<Playout>> GetFull(int id); Task<Option<Playout>> GetFull(int id);
Task<Option<PlayoutItem>> GetPlayoutItem(int channelId, DateTimeOffset now); Task<Option<PlayoutItem>> GetPlayoutItem(int channelId, DateTimeOffset now);
Task<Option<DateTimeOffset>> GetNextItemStart(int channelId, DateTimeOffset now);
Task<List<PlayoutItem>> GetPlayoutItems(int playoutId); Task<List<PlayoutItem>> GetPlayoutItems(int playoutId);
Task<List<Playout>> GetAll(); Task<List<Playout>> GetAll();
Task Update(Playout playout); Task Update(Playout playout);
@@ -44,8 +44,8 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
.OrderBy(p => p.Id) // https://github.com/dotnet/efcore/issues/22579#issuecomment-694772289 .OrderBy(p => p.Id) // https://github.com/dotnet/efcore/issues/22579#issuecomment-694772289
.SingleOrDefaultAsync(p => p.Id == id); .SingleOrDefaultAsync(p => p.Id == id);
public async Task<Option<PlayoutItem>> GetPlayoutItem(int channelId, DateTimeOffset now) => public Task<Option<PlayoutItem>> GetPlayoutItem(int channelId, DateTimeOffset now) =>
await _dbContext.PlayoutItems _dbContext.PlayoutItems
.Where(pi => pi.Playout.ChannelId == channelId) .Where(pi => pi.Playout.ChannelId == channelId)
.Where(pi => pi.Start <= now.UtcDateTime && pi.Finish > now.UtcDateTime) .Where(pi => pi.Start <= now.UtcDateTime && pi.Finish > now.UtcDateTime)
.Include(i => i.MediaItem) .Include(i => i.MediaItem)
@@ -55,7 +55,17 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
.ThenInclude(mi => (mi as Movie).MediaVersions) .ThenInclude(mi => (mi as Movie).MediaVersions)
.ThenInclude(mv => mv.MediaFiles) .ThenInclude(mv => mv.MediaFiles)
.AsNoTracking() .AsNoTracking()
.SingleOrDefaultAsync(); .SingleOrDefaultAsync()
.Map(Optional);
public Task<Option<DateTimeOffset>> GetNextItemStart(int channelId, DateTimeOffset now) =>
_dbContext.PlayoutItems
.Where(pi => pi.Playout.ChannelId == channelId)
.Where(pi => pi.Finish > now.UtcDateTime)
.OrderBy(pi => pi.Finish)
.FirstOrDefaultAsync()
.Map(Optional)
.MapT(pi => pi.StartOffset);
public Task<List<PlayoutItem>> GetPlayoutItems(int playoutId) => public Task<List<PlayoutItem>> GetPlayoutItems(int playoutId) =>
_dbContext.PlayoutItems _dbContext.PlayoutItems