Browse Source

use output duration flag (#49)

* re-enable output duration flag

* calculate appropriate duration for offline image
pull/50/head
Jason Dove 5 years ago committed by GitHub
parent
commit
5244d5076a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs
  2. 10
      ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs
  3. 14
      ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs
  4. 1
      ErsatzTV.Core/Interfaces/Repositories/IPlayoutRepository.cs
  5. 16
      ErsatzTV.Infrastructure/Data/Repositories/PlayoutRepository.cs

11
ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs

@ -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);
}); });
} }

10
ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs

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

14
ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs

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

1
ErsatzTV.Core/Interfaces/Repositories/IPlayoutRepository.cs

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

16
ErsatzTV.Infrastructure/Data/Repositories/PlayoutRepository.cs

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

Loading…
Cancel
Save