Browse Source

wait for two initial segments in playback troubleshooting (#2532)

pull/2534/head
Jason Dove 10 months ago committed by GitHub
parent
commit
f41f4b19d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 1
      ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs
  3. 1
      ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs
  4. 44
      ErsatzTV.Core.Tests/FFmpeg/FFmpegPlaybackSettingsCalculatorTests.cs
  5. 12
      ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
  6. 2
      ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettings.cs
  7. 3
      ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs
  8. 1
      ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs
  9. 1
      ErsatzTV.Core/Interfaces/FFmpeg/IFFmpegProcessService.cs
  10. 6
      ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs
  11. 2
      ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs
  12. 4
      ErsatzTV.FFmpeg/State/AudioState.cs
  13. 2
      ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs
  14. 35
      ErsatzTV/Controllers/Api/TroubleshootController.cs

1
CHANGELOG.md

@ -33,6 +33,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Dramatically improve stream startup time - Dramatically improve stream startup time
- VAAPI: fix scaling image-based subtitles (e.g. dvdsub) - VAAPI: fix scaling image-based subtitles (e.g. dvdsub)
- Fix HLS Segmenter (fmp4) on Windows - Fix HLS Segmenter (fmp4) on Windows
- Playback troubleshooting: wait for at least 2 initial segments (up to configured initial segment count) to reduce stalls
### Changed ### Changed
- Do not use graphics engine for single, permanent watermark - Do not use graphics engine for single, permanent watermark

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

@ -430,7 +430,6 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
: StreamInputKind.Vod, : StreamInputKind.Vod,
playoutItemWithPath.PlayoutItem.FillerKind, playoutItemWithPath.PlayoutItem.FillerKind,
inPoint, inPoint,
outPoint,
request.ChannelStartTime, request.ChannelStartTime,
request.PtsOffset, request.PtsOffset,
request.TargetFramerate, request.TargetFramerate,

1
ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs

@ -246,7 +246,6 @@ public class PrepareTroubleshootingPlaybackHandler(
mediaItem is RemoteStream { IsLive: true } ? StreamInputKind.Live : StreamInputKind.Vod, mediaItem is RemoteStream { IsLive: true } ? StreamInputKind.Live : StreamInputKind.Vod,
FillerKind.None, FillerKind.None,
inPoint, inPoint,
outPoint,
channelStartTime: DateTimeOffset.Now, channelStartTime: DateTimeOffset.Now,
0, 0,
None, None,

44
ErsatzTV.Core.Tests/FFmpeg/FFmpegPlaybackSettingsCalculatorTests.cs

@ -29,7 +29,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -50,7 +49,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -75,7 +73,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -96,7 +93,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -117,7 +113,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -138,7 +133,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -161,7 +155,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -184,7 +177,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -205,7 +197,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -228,7 +219,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
now, now,
now.AddMinutes(5), now.AddMinutes(5),
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -252,7 +242,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
now, now,
now.AddMinutes(5), now.AddMinutes(5),
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -280,7 +269,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -307,7 +295,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -334,7 +321,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -362,7 +348,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -389,7 +374,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -419,7 +403,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -450,7 +433,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -480,7 +462,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -510,7 +491,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -540,7 +520,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -572,7 +551,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -603,7 +581,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -634,7 +611,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -664,7 +640,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -695,7 +670,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -725,7 +699,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -756,7 +729,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -782,7 +754,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -806,7 +777,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -830,7 +800,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -855,7 +824,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -880,7 +848,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -905,7 +872,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -930,7 +896,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -954,7 +919,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -978,7 +942,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -987,7 +950,7 @@ public class FFmpegPlaybackSettingsCalculatorTests
} }
[Test] [Test]
public void Should_SetAudioDuration_With_CorrectFormat_ForTransportStream() public void Should_SetPadAudio_ForTransportStream()
{ {
FFmpegProfile ffmpegProfile = TestProfile() with FFmpegProfile ffmpegProfile = TestProfile() with
{ {
@ -1008,12 +971,11 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.FromMinutes(2),
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
actual.AudioDuration.IfNone(TimeSpan.MinValue).ShouldBe(TimeSpan.FromMinutes(2)); actual.PadAudio.ShouldBe(true);
} }
[Test] [Test]
@ -1032,7 +994,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);
@ -1058,7 +1019,6 @@ public class FFmpegPlaybackSettingsCalculatorTests
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now, DateTimeOffset.Now,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
None); None);

12
ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

@ -81,7 +81,6 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
StreamInputKind streamInputKind, StreamInputKind streamInputKind,
FillerKind fillerKind, FillerKind fillerKind,
TimeSpan inPoint, TimeSpan inPoint,
TimeSpan outPoint,
DateTimeOffset channelStartTime, DateTimeOffset channelStartTime,
long ptsOffset, long ptsOffset,
Option<int> targetFramerate, Option<int> targetFramerate,
@ -102,7 +101,6 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
start, start,
now, now,
inPoint, inPoint,
outPoint,
hlsRealtime, hlsRealtime,
streamInputKind, streamInputKind,
targetFramerate); targetFramerate);
@ -184,7 +182,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
playbackSettings.AudioBitrate, playbackSettings.AudioBitrate,
playbackSettings.AudioBufferSize, playbackSettings.AudioBufferSize,
playbackSettings.AudioSampleRate, playbackSettings.AudioSampleRate,
videoPath == audioPath ? playbackSettings.AudioDuration : Option<TimeSpan>.None, videoPath == audioPath,
playbackSettings.NormalizeLoudnessMode switch playbackSettings.NormalizeLoudnessMode switch
{ {
NormalizeLoudnessMode.LoudNorm => AudioFilter.LoudNorm, NormalizeLoudnessMode.LoudNorm => AudioFilter.LoudNorm,
@ -239,7 +237,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
// when no audio streams are available, use null audio source // when no audio streams are available, use null audio source
if (!audioVersion.MediaVersion.Streams.Any(s => s.MediaStreamKind is MediaStreamKind.Audio)) if (!audioVersion.MediaVersion.Streams.Any(s => s.MediaStreamKind is MediaStreamKind.Audio))
{ {
audioInputFile = new NullAudioInputFile(audioState with { AudioDuration = playbackSettings.AudioDuration }); audioInputFile = new NullAudioInputFile(audioState with { PadAudio = playbackSettings.PadAudio });
} }
OutputFormatKind outputFormat = OutputFormatKind.MpegTs; OutputFormatKind outputFormat = OutputFormatKind.MpegTs;
@ -599,7 +597,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
playbackSettings.AudioBitrate, playbackSettings.AudioBitrate,
playbackSettings.AudioBufferSize, playbackSettings.AudioBufferSize,
playbackSettings.AudioSampleRate, playbackSettings.AudioSampleRate,
Option<TimeSpan>.None, false,
AudioFilter.None); AudioFilter.None);
string videoFormat = GetVideoFormat(playbackSettings); string videoFormat = GetVideoFormat(playbackSettings);
@ -789,7 +787,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
channel.FFmpegProfile, channel.FFmpegProfile,
Option<int>.None); Option<int>.None);
playbackSettings.AudioDuration = Option<TimeSpan>.None; playbackSettings.PadAudio = false;
string audioFormat = playbackSettings.AudioFormat switch string audioFormat = playbackSettings.AudioFormat switch
{ {
@ -805,7 +803,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
playbackSettings.AudioBitrate, playbackSettings.AudioBitrate,
playbackSettings.AudioBufferSize, playbackSettings.AudioBufferSize,
playbackSettings.AudioSampleRate, playbackSettings.AudioSampleRate,
Option<TimeSpan>.None, false,
playbackSettings.NormalizeLoudnessMode switch playbackSettings.NormalizeLoudnessMode switch
{ {
// TODO: NormalizeLoudnessMode.LoudNorm => AudioFilter.LoudNorm, // TODO: NormalizeLoudnessMode.LoudNorm => AudioFilter.LoudNorm,

2
ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettings.cs

@ -23,7 +23,7 @@ public class FFmpegPlaybackSettings
public Option<int> AudioBufferSize { get; set; } public Option<int> AudioBufferSize { get; set; }
public Option<int> AudioChannels { get; set; } public Option<int> AudioChannels { get; set; }
public Option<int> AudioSampleRate { get; set; } public Option<int> AudioSampleRate { get; set; }
public Option<TimeSpan> AudioDuration { get; set; } public bool PadAudio { get; set; }
public FFmpegProfileAudioFormat AudioFormat { get; set; } public FFmpegProfileAudioFormat AudioFormat { get; set; }
public bool Deinterlace { get; set; } public bool Deinterlace { get; set; }
public Option<int> VideoTrackTimeScale { get; set; } public Option<int> VideoTrackTimeScale { get; set; }

3
ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs

@ -50,7 +50,6 @@ public static class FFmpegPlaybackSettingsCalculator
DateTimeOffset start, DateTimeOffset start,
DateTimeOffset now, DateTimeOffset now,
TimeSpan inPoint, TimeSpan inPoint,
TimeSpan outPoint,
bool hlsRealtime, bool hlsRealtime,
StreamInputKind streamInputKind, StreamInputKind streamInputKind,
Option<int> targetFramerate) Option<int> targetFramerate)
@ -168,7 +167,7 @@ public static class FFmpegPlaybackSettingsCalculator
result.AudioBufferSize = ffmpegProfile.AudioBufferSize; result.AudioBufferSize = ffmpegProfile.AudioBufferSize;
result.AudioChannels = ffmpegProfile.AudioChannels; result.AudioChannels = ffmpegProfile.AudioChannels;
result.AudioSampleRate = ffmpegProfile.AudioSampleRate; result.AudioSampleRate = ffmpegProfile.AudioSampleRate;
result.AudioDuration = outPoint - inPoint; result.PadAudio = true;
result.NormalizeLoudnessMode = ffmpegProfile.NormalizeLoudnessMode; result.NormalizeLoudnessMode = ffmpegProfile.NormalizeLoudnessMode;
result.Deinterlace = ffmpegProfile.DeinterlaceVideo == true && result.Deinterlace = ffmpegProfile.DeinterlaceVideo == true &&

1
ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs

@ -84,7 +84,6 @@ public class FFmpegProcessService
DateTimeOffset.UnixEpoch, DateTimeOffset.UnixEpoch,
DateTimeOffset.UnixEpoch, DateTimeOffset.UnixEpoch,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.Zero,
false, false,
StreamInputKind.Vod, StreamInputKind.Vod,
Option<int>.None); Option<int>.None);

1
ErsatzTV.Core/Interfaces/FFmpeg/IFFmpegProcessService.cs

@ -36,7 +36,6 @@ public interface IFFmpegProcessService
StreamInputKind streamInputKind, StreamInputKind streamInputKind,
FillerKind fillerKind, FillerKind fillerKind,
TimeSpan inPoint, TimeSpan inPoint,
TimeSpan outPoint,
DateTimeOffset channelStartTime, DateTimeOffset channelStartTime,
long ptsOffset, long ptsOffset,
Option<int> targetFramerate, Option<int> targetFramerate,

6
ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs

@ -52,7 +52,7 @@ public class PipelineBuilderBaseTests
320, 320,
640, 640,
48, 48,
Option<TimeSpan>.None, false,
AudioFilter.None)); AudioFilter.None));
var desiredState = new FrameState( var desiredState = new FrameState(
@ -151,7 +151,7 @@ public class PipelineBuilderBaseTests
320, 320,
640, 640,
48, 48,
Option<TimeSpan>.None, false,
AudioFilter.None)); AudioFilter.None));
var desiredState = new FrameState( var desiredState = new FrameState(
@ -308,7 +308,7 @@ public class PipelineBuilderBaseTests
None, None,
None, None,
None, None,
None, false,
AudioFilter.None)); AudioFilter.None));
var desiredState = new FrameState( var desiredState = new FrameState(

2
ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs

@ -467,7 +467,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
audioInputFile.FilterSteps.Add(new AudioResampleFilter()); audioInputFile.FilterSteps.Add(new AudioResampleFilter());
} }
foreach (TimeSpan _ in audioInputFile.DesiredState.AudioDuration) if (audioInputFile.DesiredState.PadAudio)
{ {
audioInputFile.FilterSteps.Add(new AudioPadFilter()); audioInputFile.FilterSteps.Add(new AudioPadFilter());
} }

4
ErsatzTV.FFmpeg/State/AudioState.cs

@ -6,7 +6,7 @@ public record AudioState(
Option<int> AudioBitrate, Option<int> AudioBitrate,
Option<int> AudioBufferSize, Option<int> AudioBufferSize,
Option<int> AudioSampleRate, Option<int> AudioSampleRate,
Option<TimeSpan> AudioDuration, bool PadAudio,
AudioFilter NormalizeLoudnessFilter) AudioFilter NormalizeLoudnessFilter)
{ {
public static readonly AudioState Copy = new( public static readonly AudioState Copy = new(
@ -15,7 +15,7 @@ public record AudioState(
Option<int>.None, Option<int>.None,
Option<int>.None, Option<int>.None,
Option<int>.None, Option<int>.None,
Option<TimeSpan>.None, false,
AudioFilter.None AudioFilter.None
); );
} }

2
ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs

@ -395,7 +395,6 @@ public class TranscodingTests
StreamInputKind.Vod, StreamInputKind.Vod,
FillerKind.None, FillerKind.None,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.FromSeconds(3),
DateTimeOffset.Now, DateTimeOffset.Now,
0, 0,
None, None,
@ -707,7 +706,6 @@ public class TranscodingTests
StreamInputKind.Vod, StreamInputKind.Vod,
FillerKind.None, FillerKind.None,
TimeSpan.Zero, TimeSpan.Zero,
TimeSpan.FromSeconds(3),
DateTimeOffset.Now, DateTimeOffset.Now,
0, 0,
None, None,

35
ErsatzTV/Controllers/Api/TroubleshootController.cs

@ -7,6 +7,7 @@ using ErsatzTV.Core;
using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.FFmpeg; using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Metadata; using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Troubleshooting; using ErsatzTV.Core.Interfaces.Troubleshooting;
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -18,6 +19,7 @@ namespace ErsatzTV.Controllers.Api;
public class TroubleshootController( public class TroubleshootController(
ChannelWriter<IFFmpegWorkerRequest> channelWriter, ChannelWriter<IFFmpegWorkerRequest> channelWriter,
ILocalFileSystem localFileSystem, ILocalFileSystem localFileSystem,
IConfigElementRepository configElementRepository,
ITroubleshootingNotifier notifier, ITroubleshootingNotifier notifier,
IMediator mediator) : ControllerBase IMediator mediator) : ControllerBase
{ {
@ -94,20 +96,41 @@ public class TroubleshootController(
troubleshootingInfo), troubleshootingInfo),
cancellationToken); cancellationToken);
string playlistFile = Path.Combine( string playlistFile = Path.Combine(FileSystemLayout.TranscodeTroubleshootingFolder, "live.m3u8");
FileSystemLayout.TranscodeFolder,
".troubleshooting",
"live.m3u8");
while (!localFileSystem.FileExists(playlistFile)) while (!localFileSystem.FileExists(playlistFile))
{ {
await Task.Delay(TimeSpan.FromMilliseconds(250), cancellationToken); await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken);
if (cancellationToken.IsCancellationRequested || notifier.IsFailed(sessionId)) if (cancellationToken.IsCancellationRequested || notifier.IsFailed(sessionId))
{ {
break; break;
} }
} }
int initialSegmentCount = await configElementRepository
.GetValue<int>(ConfigElementKey.FFmpegInitialSegmentCount, cancellationToken)
.Map(maybeCount => maybeCount.Match(c => c, () => 1));
initialSegmentCount = Math.Max(initialSegmentCount, 2);
bool hasSegments = false;
while (!hasSegments)
{
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken);
string[] segmentFiles = streamingMode switch
{
StreamingMode.HttpLiveStreamingSegmenterFmp4 => Directory.GetFiles(
FileSystemLayout.TranscodeTroubleshootingFolder,
"*.m4s"),
_ => Directory.GetFiles(FileSystemLayout.TranscodeTroubleshootingFolder, "*.ts")
};
if (segmentFiles.Length >= initialSegmentCount)
{
hasSegments = true;
}
}
if (!notifier.IsFailed(sessionId)) if (!notifier.IsFailed(sessionId))
{ {
return Redirect("~/iptv/session/.troubleshooting/live.m3u8"); return Redirect("~/iptv/session/.troubleshooting/live.m3u8");

Loading…
Cancel
Save