Browse Source

lower gop size and keyframe interval (#2832)

* lower gop size and keyframe interval

* update changelog

* fix build using latest dotnet sdk

* fixes
pull/2835/head
Jason Dove 2 months ago committed by GitHub
parent
commit
08cbf59527
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      .github/workflows/artifacts.yml
  2. 8
      .github/workflows/pr.yml
  3. 2
      CHANGELOG.md
  4. 2
      ErsatzTV.Application/ErsatzTV.Application.csproj
  5. 4
      ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs
  6. 2
      ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj
  7. 2
      ErsatzTV.Core/ErsatzTV.Core.csproj
  8. 2
      ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
  9. 2
      ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj
  10. 4
      ErsatzTV.FFmpeg/OutputFormat/OutputFormatConcatHls.cs
  11. 7
      ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs
  12. 2
      ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj
  13. 27
      ErsatzTV.Infrastructure/Data/DbInitializer.cs
  14. 2
      ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj
  15. 4
      ErsatzTV.Infrastructure/Metadata/LanguageCodeCache.cs
  16. 2
      ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj
  17. 1
      ErsatzTV.Scanner/ErsatzTV.Scanner.csproj
  18. 2
      ErsatzTV/ErsatzTV.csproj
  19. 3
      ErsatzTV/Pages/FFmpegEditor.razor
  20. 2
      docker/Dockerfile
  21. 2
      docker/arm32v7/Dockerfile
  22. 2
      docker/arm64/Dockerfile

6
.github/workflows/artifacts.yml

@ -57,7 +57,7 @@ jobs: @@ -57,7 +57,7 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.102'
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
@ -172,7 +172,7 @@ jobs: @@ -172,7 +172,7 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.102'
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
@ -229,7 +229,7 @@ jobs: @@ -229,7 +229,7 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.102'
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear

8
.github/workflows/pr.yml

@ -14,7 +14,7 @@ jobs: @@ -14,7 +14,7 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.102'
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
@ -36,7 +36,7 @@ jobs: @@ -36,7 +36,7 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.102'
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
@ -72,7 +72,7 @@ jobs: @@ -72,7 +72,7 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.102'
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
@ -100,7 +100,7 @@ jobs: @@ -100,7 +100,7 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.102'
dotnet-version: '10.0.x'
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear

2
CHANGELOG.md

@ -20,11 +20,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -20,11 +20,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- If this feature turns out to be popular, methods to correct the drift may be investigated
- Add `ETV_INSTANCE_ID` environment variable to disambiguate EPG data from multiple ErsatzTV instances
- When set, the value will be used in channel identifiers before the final `.ersatztv.org`
- Show warning message when selecting audio format `aac (latm)` for general streaming use when it is only intended for DVB-C
### Changed
- Move dark/light mode toggle to **Settings** > **UI**
- Use latest (non-deprecated) authorization method with Jellyfin API
- Replace direct Discord links with new contact page https://ersatztv.org/contact which also includes other options like Matrix
- Lower GOP size and keyframe interval from four seconds to two seconds in accordance with HLS2 draft spec recommendations
### Fixed
- Improve stability of playback orders `Shuffle` and `Shuffle in Order` over time

2
ErsatzTV.Application/ErsatzTV.Application.csproj

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<NoWarn>VSTHRD200</NoWarn>
<NoWarn>VSTHRD200,CA1873</NoWarn>
<ImplicitUsings>enable</ImplicitUsings>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

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

@ -498,7 +498,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -498,7 +498,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
Option<TimeSpan> maybeDuration = maybeNextStart.Map(s => s - now);
// limit working ahead on errors to 1 minute
if (!request.HlsRealtime && maybeDuration.IfNone(TimeSpan.FromMinutes(2)) > TimeSpan.FromMinutes(1))
if (!request.HlsRealtime && await maybeDuration.IfNoneAsync(TimeSpan.FromMinutes(2)) > TimeSpan.FromMinutes(1))
{
maybeNextStart = now.AddMinutes(1);
maybeDuration = TimeSpan.FromMinutes(1);
@ -766,7 +766,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -766,7 +766,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
.ToListAsync(cancellationToken);
// always play min(duration to next item, version.Duration)
TimeSpan duration = maybeDuration.IfNone(version.Duration);
TimeSpan duration = await maybeDuration.IfNoneAsync(version.Duration);
if (version.Duration < duration)
{
duration = version.Duration;

2
ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<NoWarn>VSTHRD200</NoWarn>
<NoWarn>VSTHRD200,CA1873</NoWarn>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

2
ErsatzTV.Core/ErsatzTV.Core.csproj

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<NoWarn>VSTHRD200</NoWarn>
<NoWarn>VSTHRD200,CA1873</NoWarn>
<ImplicitUsings>enable</ImplicitUsings>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

2
ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

@ -893,7 +893,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -893,7 +893,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
playbackSettings.NormalizeColors,
playbackSettings.Deinterlace);
var frameRate = playbackSettings.FrameRate.IfNone(new FrameRate("24"));
var frameRate = await playbackSettings.FrameRate.IfNoneAsync(new FrameRate("24"));
var ffmpegVideoStream = new VideoStream(
0,

2
ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>VSTHRD200</NoWarn>
<NoWarn>VSTHRD200,CA1873</NoWarn>
</PropertyGroup>
<ItemGroup>

4
ErsatzTV.FFmpeg/OutputFormat/OutputFormatConcatHls.cs

@ -32,8 +32,8 @@ public class OutputFormatConcatHls : IPipelineStep @@ -32,8 +32,8 @@ public class OutputFormatConcatHls : IPipelineStep
return
[
"-g", $"{OutputFormatHls.SegmentSeconds}/2",
"-force_key_frames", $"expr:gte(t,n_forced*{OutputFormatHls.SegmentSeconds}/2)",
"-g", $"{OutputFormatHls.KeyframeIntervalSeconds}",
"-force_key_frames", $"expr:gte(t,n_forced*{OutputFormatHls.KeyframeIntervalSeconds})",
"-f", "hls",
"-hls_segment_type", segmentType,
//"-hls_init_time", "2",

7
ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs

@ -6,6 +6,7 @@ namespace ErsatzTV.FFmpeg.OutputFormat; @@ -6,6 +6,7 @@ namespace ErsatzTV.FFmpeg.OutputFormat;
public class OutputFormatHls : IPipelineStep
{
public const int SegmentSeconds = 4;
public const int KeyframeIntervalSeconds = 2;
private readonly FrameState _desiredState;
private readonly bool _isFirstTranscode;
@ -55,7 +56,7 @@ public class OutputFormatHls : IPipelineStep @@ -55,7 +56,7 @@ public class OutputFormatHls : IPipelineStep
int gop = _oneSecondGop
? (int)Math.Round(frameRate.ParsedFrameRate)
: (int)Math.Round(frameRate.ParsedFrameRate * SegmentSeconds);
: (int)Math.Round(frameRate.ParsedFrameRate * KeyframeIntervalSeconds);
List<string> result = [];
@ -64,8 +65,8 @@ public class OutputFormatHls : IPipelineStep @@ -64,8 +65,8 @@ public class OutputFormatHls : IPipelineStep
result.AddRange(
[
"-g", $"{gop}",
"-keyint_min", $"{(int)Math.Round(frameRate.ParsedFrameRate * SegmentSeconds)}",
"-force_key_frames", $"expr:gte(t,n_forced*{SegmentSeconds})"
"-keyint_min", $"{(int)Math.Round(frameRate.ParsedFrameRate * KeyframeIntervalSeconds)}",
"-force_key_frames", $"expr:gte(t,n_forced*{KeyframeIntervalSeconds})"
]);
}

2
ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>VSTHRD200</NoWarn>
<NoWarn>VSTHRD200,CA1873</NoWarn>
<IsPackable>false</IsPackable>
</PropertyGroup>

27
ErsatzTV.Infrastructure/Data/DbInitializer.cs

@ -48,25 +48,22 @@ public static class DbInitializer @@ -48,25 +48,22 @@ public static class DbInitializer
if (resource != null)
{
using var reader = new StreamReader(resource);
while (!reader.EndOfStream)
string line;
while ((line = await reader.ReadLineAsync(cancellationToken)) is not null)
{
string line = await reader.ReadLineAsync(cancellationToken);
if (line != null)
string[] split = line.Split("|");
if (split.Length == 5)
{
string[] split = line.Split("|");
if (split.Length == 5)
var languageCode = new LanguageCode
{
var languageCode = new LanguageCode
{
ThreeCode1 = split[0],
ThreeCode2 = split[1],
TwoCode = split[2],
EnglishName = split[3],
FrenchName = split[4]
};
ThreeCode1 = split[0],
ThreeCode2 = split[1],
TwoCode = split[2],
EnglishName = split[3],
FrenchName = split[4]
};
await context.LanguageCodes.AddAsync(languageCode, cancellationToken);
}
await context.LanguageCodes.AddAsync(languageCode, cancellationToken);
}
}
}

2
ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<NoWarn>VSTHRD200</NoWarn>
<NoWarn>VSTHRD200,CA1873</NoWarn>
<ImplicitUsings>enable</ImplicitUsings>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

4
ErsatzTV.Infrastructure/Metadata/LanguageCodeCache.cs

@ -21,9 +21,9 @@ public class LanguageCodeCache : ILanguageCodeCache @@ -21,9 +21,9 @@ public class LanguageCodeCache : ILanguageCodeCache
if (resource != null)
{
using var reader = new StreamReader(resource);
while (!reader.EndOfStream)
string line;
while ((line = await reader.ReadLineAsync(cancellationToken)) is not null)
{
string line = await reader.ReadLineAsync(cancellationToken);
if (string.IsNullOrWhiteSpace(line))
{
continue;

2
ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>VSTHRD200,CA1873</NoWarn>
<IsPackable>false</IsPackable>
</PropertyGroup>

1
ErsatzTV.Scanner/ErsatzTV.Scanner.csproj

@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
<UserSecretsId>729e6271-c307-43c8-8e36-1b36c39f6de2</UserSecretsId>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>VSTHRD200,CA1873</NoWarn>
</PropertyGroup>
<ItemGroup>

2
ErsatzTV/ErsatzTV.csproj

@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>VSTHRD200</NoWarn>
<NoWarn>VSTHRD200,CA1873</NoWarn>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
<Configurations>Debug;Release;Debug No Sync</Configurations>
<Platforms>AnyCPU</Platforms>

3
ErsatzTV/Pages/FFmpegEditor.razor

@ -282,8 +282,7 @@ @@ -282,8 +282,7 @@
<div class="d-flex">
<MudText>Format</MudText>
</div>
<MudSelect @bind-Value="_model.AudioFormat" For="@(() => _model.AudioFormat)">
<MudSelectItem Value="@FFmpegProfileAudioFormat.Aac">aac</MudSelectItem>
<MudSelect @bind-Value="_model.AudioFormat" For="@(() => _model.AudioFormat)" HelperText="@(_model.AudioFormat is FFmpegProfileAudioFormat.AacLatm ? "aac (latm) is ONLY intended for DVB-C; anything else should use aac instead which uses ADTS" : string.Empty)"> <MudSelectItem Value="@FFmpegProfileAudioFormat.Aac">aac</MudSelectItem>
<MudSelectItem Value="@FFmpegProfileAudioFormat.Ac3">ac3</MudSelectItem>
<MudSelectItem Value="@FFmpegProfileAudioFormat.AacLatm">aac (latm)</MudSelectItem>
</MudSelect>

2
docker/Dockerfile

@ -9,7 +9,7 @@ RUN apt-get update && \ @@ -9,7 +9,7 @@ RUN apt-get update && \
rm -rf /var/lib/apt/lists/*
# https://hub.docker.com/_/microsoft-dotnet
FROM mcr.microsoft.com/dotnet/sdk:10.0.102-noble-amd64 AS build
FROM mcr.microsoft.com/dotnet/sdk:10.0-noble-amd64 AS build
RUN apt-get update && apt-get install -y ca-certificates gnupg default-jre-headless python3-pip
WORKDIR /source

2
docker/arm32v7/Dockerfile

@ -4,7 +4,7 @@ FROM --platform=linux/arm/v7 ghcr.io/ersatztv/ersatztv-ffmpeg:7.1.1 AS runtime-b @@ -4,7 +4,7 @@ FROM --platform=linux/arm/v7 ghcr.io/ersatztv/ersatztv-ffmpeg:7.1.1 AS runtime-b
COPY --from=dotnet-runtime /usr/share/dotnet /usr/share/dotnet
# https://hub.docker.com/_/microsoft-dotnet
FROM mcr.microsoft.com/dotnet/sdk:10.0.102-noble-amd64 AS build
FROM mcr.microsoft.com/dotnet/sdk:10.0-noble-amd64 AS build
RUN apt-get update && apt-get install -y ca-certificates gnupg
WORKDIR /source

2
docker/arm64/Dockerfile

@ -4,7 +4,7 @@ FROM --platform=linux/arm64 ghcr.io/ersatztv/ersatztv-ffmpeg:7.1.1 AS runtime-ba @@ -4,7 +4,7 @@ FROM --platform=linux/arm64 ghcr.io/ersatztv/ersatztv-ffmpeg:7.1.1 AS runtime-ba
COPY --from=dotnet-runtime /usr/share/dotnet /usr/share/dotnet
# https://hub.docker.com/_/microsoft-dotnet
FROM mcr.microsoft.com/dotnet/sdk:10.0.102-noble-arm64v8 AS build
FROM mcr.microsoft.com/dotnet/sdk:10.0-noble-arm64v8 AS build
RUN apt-get update && apt-get install -y ca-certificates gnupg
WORKDIR /source

Loading…
Cancel
Save