Browse Source

reduce initial hls segmenter delay (#406)

pull/408/head
Jason Dove 5 years ago committed by GitHub
parent
commit
adc7982955
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 3
      ErsatzTV.Application/Streaming/Commands/StartFFmpegSessionHandler.cs
  3. 10
      ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs
  4. 3
      ErsatzTV.Core.Tests/FFmpeg/TranscodingTests.cs
  5. 17
      ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs
  6. 5
      ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs
  7. 2
      ErsatzTV.Core/FFmpeg/FFmpegSegmenterService.cs

2
CHANGELOG.md

@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Changed
- Reduce initial `HLS Segmenter` delay from 5 seconds to 3 seconds
## [0.1.0-alpha] - 2021-10-08
### Added

3
ErsatzTV.Application/Streaming/Commands/StartFFmpegSessionHandler.cs

@ -5,6 +5,7 @@ using System.Threading.Channels; @@ -5,6 +5,7 @@ using System.Threading.Channels;
using System.Threading.Tasks;
using ErsatzTV.Core;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.FFmpeg;
using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Metadata;
using LanguageExt;
@ -45,7 +46,7 @@ namespace ErsatzTV.Application.Streaming.Commands @@ -45,7 +46,7 @@ namespace ErsatzTV.Application.Streaming.Commands
await _channel.WriteAsync(request);
// TODO: find some other way to let ffmpeg get ahead
await Task.Delay(TimeSpan.FromSeconds(5));
await Task.Delay(FFmpegSegmenterService.SegmenterDelay);
return Unit.Default;
}

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

@ -54,7 +54,12 @@ namespace ErsatzTV.Application.Streaming.Queries @@ -54,7 +54,12 @@ namespace ErsatzTV.Application.Streaming.Queries
Channel channel,
string ffmpegPath)
{
DateTimeOffset now = DateTimeOffset.Now;
DateTimeOffset now = request.Mode switch
{
"segmenter" => DateTimeOffset.Now + FFmpegSegmenterService.SegmenterDelay,
_ => DateTimeOffset.Now
};
Either<BaseError, PlayoutItemWithPath> maybePlayoutItem = await dbContext.PlayoutItems
.Include(i => i.MediaItem)
.ThenInclude(mi => (mi as Episode).MediaVersions)
@ -113,7 +118,8 @@ namespace ErsatzTV.Application.Streaming.Queries @@ -113,7 +118,8 @@ namespace ErsatzTV.Application.Streaming.Queries
playoutItemWithPath.PlayoutItem.StartOffset,
request.StartAtZero ? playoutItemWithPath.PlayoutItem.StartOffset : now,
maybeGlobalWatermark,
maybeVaapiDriver));
maybeVaapiDriver,
request.StartAtZero));
},
async error =>
{

3
ErsatzTV.Core.Tests/FFmpeg/TranscodingTests.cs

@ -184,7 +184,8 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -184,7 +184,8 @@ namespace ErsatzTV.Core.Tests.FFmpeg
now,
now,
None,
None);
None,
false);
process.StartInfo.RedirectStandardError = true;

17
ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs

@ -310,8 +310,11 @@ namespace ErsatzTV.Core.FFmpeg @@ -310,8 +310,11 @@ namespace ErsatzTV.Core.FFmpeg
return this;
}
public FFmpegProcessBuilder WithHls(string channelNumber, MediaVersion mediaVersion)
public FFmpegProcessBuilder WithHls(string channelNumber, MediaVersion mediaVersion, bool startAtZero)
{
const int INITIAL_SEGMENT_SECONDS = 1;
const int SUBSEQUENT_SEGMENT_SECONDS = 2;
if (!int.TryParse(mediaVersion.RFrameRate, out int frameRate))
{
string[] split = (mediaVersion.RFrameRate ?? string.Empty).Split("/");
@ -326,15 +329,17 @@ namespace ErsatzTV.Core.FFmpeg @@ -326,15 +329,17 @@ namespace ErsatzTV.Core.FFmpeg
}
}
int segmentSeconds = startAtZero ? SUBSEQUENT_SEGMENT_SECONDS : INITIAL_SEGMENT_SECONDS;
_arguments.AddRange(
new[]
{
"-g", $"{frameRate * 2}",
"-keyint_min", $"{frameRate * 2}",
// "-force_key_frames",
// "expr:gte(t,n_forced*2)",
"-use_wallclock_as_timestamps", "1",
"-g", $"{frameRate * segmentSeconds}",
"-keyint_min", $"{frameRate * segmentSeconds}",
"-force_key_frames", $"expr:gte(t,n_forced*{segmentSeconds})",
"-f", "hls",
"-hls_time", "2",
"-hls_time", $"{segmentSeconds}",
"-hls_list_size", "10",
"-segment_list_flags", "+live",
"-hls_flags", "delete_segments+program_date_time+append_list+discont_start+omit_endlist",

5
ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs

@ -39,7 +39,8 @@ namespace ErsatzTV.Core.FFmpeg @@ -39,7 +39,8 @@ namespace ErsatzTV.Core.FFmpeg
DateTimeOffset start,
DateTimeOffset now,
Option<ChannelWatermark> globalWatermark,
Option<VaapiDriver> maybeVaapiDriver)
Option<VaapiDriver> maybeVaapiDriver,
bool startAtZero)
{
MediaStream videoStream = await _ffmpegStreamSelector.SelectVideoStream(channel, version);
Option<MediaStream> maybeAudioStream = await _ffmpegStreamSelector.SelectAudioStream(channel, version);
@ -118,7 +119,7 @@ namespace ErsatzTV.Core.FFmpeg @@ -118,7 +119,7 @@ namespace ErsatzTV.Core.FFmpeg
{
// HLS needs to segment and generate playlist
case StreamingMode.HttpLiveStreamingSegmenter:
return builder.WithHls(channel.Number, version)
return builder.WithHls(channel.Number, version, startAtZero)
.Build();
default:
return builder.WithFormat("mpegts")

2
ErsatzTV.Core/FFmpeg/FFmpegSegmenterService.cs

@ -12,6 +12,8 @@ namespace ErsatzTV.Core.FFmpeg @@ -12,6 +12,8 @@ namespace ErsatzTV.Core.FFmpeg
{
public class FFmpegSegmenterService : IFFmpegSegmenterService
{
public static readonly TimeSpan SegmenterDelay = TimeSpan.FromSeconds(3);
private static readonly ConcurrentDictionary<string, ProcessAndToken> Processes = new();
private readonly ILogger<FFmpegSegmenterService> _logger;

Loading…
Cancel
Save